<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Planet Raku</title>
  <link rel="alternate" href="http://planet.raku.org/" type="text/html"/>
  <subtitle>Raku RSS Feeds</subtitle>
  <author>
    <name>Elizabeth Mattijsen (Libera: lizmat #raku)</name>
    <email></email>
  </author>
  <updated>2026-04-13T19:25:33Z</updated>
  <link rel="self" href="http://planet.raku.org/" type="application/atom+xml"/>
  <id>http://planet.raku.org/</id>
  <entry>
    <title>2026.15 Hugs &amp; Busses</title>
    <link rel="alternate" href="https://rakudoweekly.blog/2026/04/13/2026-15-hugs-busses/" type="text/html"/>
    <content type="html">
&lt;p class="has-small-font-size wp-block-paragraph"&gt;Post image attribution: Eddie Leslie from Lancashire, CC BY-SA 2.0 &lt;a href="https://creativecommons.org/licenses/by-sa/2.0"&gt;https://creativecommons.org/licenses/by-sa/2.0&lt;/a&gt;, via Wikimedia Commons&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Whateverables Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;This week sees the release of 3 (yes, 3) new &lt;a href="https://github.com/Raku/whateverable/wiki"&gt;Whateverables&lt;/a&gt;.&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://github.com/Raku/whateverable/wiki/Linkable"&gt;Linkable&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/Raku/whateverable/wiki/Buildable"&gt;Buildable&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/Raku/whateverable/wiki/Huggable"&gt;Huggable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"&gt;
&lt;p class="wp-block-paragraph"&gt;The Whateverables are a collection of IRC bots primarily useful for Raku developers. They are written in Raku and are based on IRC::Client. Many of the use cases involve running Raku code using pre-built versions of the Rakudo compiler for each commit.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p class="wp-block-paragraph"&gt;They work over the IRC-Discord bridge too mostly (make sure you are in the main #raku channel and note that sometimes the gremlins can get under the bridge &amp;#8211; or is that the trolls).&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Oh &amp;#8211; and have something for the weekly? Then the &lt;a href="https://github.com/Raku/whateverable/wiki/Notable"&gt;Notable&lt;/a&gt; bot can be fed using &lt;code&gt;weekly: my hot news&lt;/code&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;TPRC Submit your Talk&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Don’t Miss the Perl and Raku Conference 2026 in Greenville, SC&lt;br&gt;SAVE THE DATES! Friday through Sunday, June 26-28&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Registration is open: &lt;a href="https://tprc.us/tprc-2026-gsp"&gt;https://tprc.us/tprc-2026-gsp&lt;/a&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Weekly Challenge&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-369"&gt;Weekly Challenge #369&lt;/a&gt; is available for your giggles.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Raku Tips &amp;#8216;n Tricks&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;This week, my eye was caught by an &lt;a href="https://www.quora.com/Why-do-we-use-variables-in-programming-languages"&gt;interesting post&lt;/a&gt; on Quora by Jan M Savage: &lt;em&gt;Why do we use variables in programming languages?&lt;/em&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Variables capture data that we can re-use, but more importantly, judicious use of variables lets our code tell a story. &lt;/em&gt;&lt;/p&gt;



&lt;div style="font-weight: 500 .nohighlights { background" class="raku-code"&gt;&lt;div&gt;&lt;pre class="nohighlights" style="font-size: 1em;font-family: monospace"&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;sub&lt;/span&gt;&amp;nbsp;sec-parser(&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$secs&lt;/span&gt;)&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$rsecs&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$secs&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;mod&lt;/span&gt;&amp;nbsp;60;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$rmins&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;&amp;nbsp;(&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$secs&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;div&lt;/span&gt;&amp;nbsp;60)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;mod&lt;/span&gt;&amp;nbsp;60;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$rhrs&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;((&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$secs&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;div&lt;/span&gt;&amp;nbsp;60)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;div&lt;/span&gt;&amp;nbsp;60)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;mod&lt;/span&gt;&amp;nbsp;24;&amp;nbsp;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$days&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;((&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$secs&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;div&lt;/span&gt;&amp;nbsp;60)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;div&lt;/span&gt;&amp;nbsp;60)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;div&lt;/span&gt;&amp;nbsp;24;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$days&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$rhrs&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$rmins&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$rsecs&lt;/span&gt;);&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;span style="color: #489fdc" class="rainbow-routine"&gt;say&lt;/span&gt;&amp;nbsp;sec-parser(240_000);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #4aa36c" class="rainbow-comment"&gt;# (days =&amp;gt; 2 hrs =&amp;gt; 18 mins =&amp;gt; 40 secs =&amp;gt; 0)&lt;br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Of course, you’ve made use of variables (declared with my) in order to capture data, but: your code is not telling a story since the variables are poorly named; pray what is rhrs???&lt;/em&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Jan will show you how to write the same function such that all the div and mod operations occur underground (so to speak), so that all you can see is what matters:&lt;/em&gt;&lt;/p&gt;



&lt;div style="font-weight: 500 .nohighlights { background" class="raku-code"&gt;&lt;div&gt;&lt;pre class="nohighlights" style="font-size: 1em;font-family: monospace"&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;sub&lt;/span&gt;&amp;nbsp;sec-parser(&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$total-sec&lt;/span&gt;)&amp;nbsp;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;(&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$secs&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$mins&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$hrs&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$days&lt;/span&gt;)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$total-sec&lt;/span&gt;.&lt;span style="color: #489fdc" class="rainbow-routine"&gt;polymod&lt;/span&gt;(60&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;60&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;24);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$days&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$hrs&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$mins&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #2458a2" class="rainbow-name_scalar"&gt;$secs&lt;/span&gt;);&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;span style="color: #489fdc" class="rainbow-routine"&gt;say&lt;/span&gt;&amp;nbsp;sec-parser(240_000);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #4aa36c" class="rainbow-comment"&gt;#(days =&amp;gt; 2 hrs =&amp;gt; 18 mins =&amp;gt; 40 secs =&amp;gt; 0)&lt;br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;



&lt;p class="wp-block-paragraph"&gt;This code shows off a cool set of Raku features:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Destructuring into a list &lt;code&gt;my&lt;/code&gt; declaration&lt;/li&gt;



&lt;li&gt;the &lt;code&gt;.polymod&lt;/code&gt; method to apply the &lt;code&gt;mod&lt;/code&gt; operation multiple times&lt;/li&gt;



&lt;li&gt;use of the Pair colon syntax &lt;code&gt;:$hrs&lt;/code&gt; to output the name and value of each item&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;Very nice &amp;#8211; thanks to Jan for combining great advice on variables and showing off some Raku.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Your contribution is welcome, please make a gist and share via the #raku channel on IRC or Discord.&lt;/em&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Questions About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/rakulang/comments/1sh2lt6/destructuring_and_placeholders/"&gt;destructuring and placeholders&lt;/a&gt; by &lt;em&gt;jaldhar&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Comments About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/gellyfish.uk/post/3mj7r2emurs2q"&gt;a thing in #RakuLang to see what was going on the Bluesky firehose feed&lt;/a&gt; by &lt;em&gt;Jonathan Stowe&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://bsky.app/profile/gellyfish.uk/post/3mjaiyjaqcs25"&gt;a #RakuLang thingy to put the stats from the Bluesky firehose feed on the web&lt;/a&gt; by &lt;em&gt;Jonathan Stowe&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://bsky.app/profile/librasteve.bsky.social/post/3mj7glrgb3s2s"&gt;some fun Artemis II armchair physics using the CragCLI calculator&lt;/a&gt; by &lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://mastodon.social/@avuserow@fosstodon.org/116395489116604209"&gt;a #rakulang terminal emulator heavily inspired by #XMonad&lt;/a&gt; by &lt;em&gt;Adrian&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://mastodon.social/@leobm@norden.social/116363255346444024"&gt;I actually find e.g. #Rakulang&amp;#8217;s approach quite interesting too&lt;/a&gt; by &lt;em&gt;Felix&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://www.reddit.com/r/ProgrammingLanguages/comments/1sj50w0/comment/ofuj51j/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button"&gt;If you want a language that is full on transparently Unicode&lt;/a&gt; by &lt;em&gt;b2gills&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://www.reddit.com/r/programming/comments/1sfnk1y/comment/oeysahj/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button"&gt;see what people who take their regex seriously came up with&lt;/a&gt; by &lt;em&gt;Huxton_2021&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://qr.ae/pFpq9A"&gt;judicious use of variables lets our code tell a story&lt;/a&gt; by &lt;em&gt;Jan M. Savage&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;div&gt;
&lt;h3&gt;New Doc &amp;amp; Web Pull Requests&lt;/h3&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/314"&gt;fix broken links to /nav/1&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/312"&gt;Stubs&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3 class="wp-block-heading"&gt;New Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/LLM::Resources"&gt;LLM::Resources&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/WWW::HorizonsEphemerisSystem"&gt;WWW::HorizonsEphemerisSystem&lt;/a&gt; by
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:apogee/ComfyUI::API"&gt;ComfyUI::API&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/Roaring::Tags"&gt;Roaring::Tags&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/HuggingFace::API"&gt;HuggingFace::API&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/CRoaring"&gt;CRoaring&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/Template::Jinja2"&gt;Template::Jinja2&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/LLM::Data::ContentTag"&gt;LLM::Data::ContentTag&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/LLM::Data::Inference"&gt;LLM::Data::Inference&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/Selkie"&gt;Selkie&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/LLM::Chat::Backend"&gt;LLM::Chat::Backend&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/MCP::Server"&gt;MCP::Server&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/Notcurses::Native"&gt;Notcurses::Native&lt;/a&gt; by
&lt;em&gt;Matt Doughty&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Updated Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/LLM::Functions"&gt;LLM::Functions&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/DSL::Examples"&gt;DSL::Examples&lt;/a&gt; by 
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:dwarring/PDF::Tags"&gt;PDF::Tags&lt;/a&gt;,
&lt;a href="https://raku.land/zef:dwarring/Pod::To::PDF"&gt;Pod::To::PDF&lt;/a&gt;,
&lt;a href="https://raku.land/zef:dwarring/PDF::Tags::Reader"&gt;PDF::Tags::Reader&lt;/a&gt; by 
&lt;em&gt;David Warring&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:tony-o/Data::Dump"&gt;Data::Dump&lt;/a&gt; by 
&lt;em&gt;Tony O&amp;#039;Dell&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:librasteve/Air"&gt;Air&lt;/a&gt; by 
&lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:raku-community-modules/DBIish"&gt;DBIish&lt;/a&gt; by 
&lt;em&gt;Various Artistes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:apogee/Monad"&gt;Monad&lt;/a&gt;,
&lt;a href="https://raku.land/zef:apogee/LLM::Chat"&gt;LLM::Chat&lt;/a&gt; by
&lt;em&gt;Matt Doughty&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:lizmat/rak"&gt;rak&lt;/a&gt;,
&lt;a href="https://raku.land/zef:lizmat/P5pack"&gt;P5pack&lt;/a&gt;,
&lt;a href="https://raku.land/zef:lizmat/P5built-ins"&gt;P5built-ins&lt;/a&gt; by 
&lt;em&gt;Elizabeth Mattijsen&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:sp1983/Sparrowdo"&gt;Sparrowdo&lt;/a&gt;,
&lt;a href="https://raku.land/zef:sp1983/Sparrow6"&gt;Sparrow6&lt;/a&gt; by 
&lt;em&gt;sp1983&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://github.com/lizmat/articles/blob/main/weekly-2022.51.md#winding-down"&gt;&lt;/a&gt;Winding down&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;As we say in London, it&amp;#8217;s like you wait forever for a bus and then 3 come along all at once. So it is with the spasm of activity this week on Whateverables (the last updates to that wiki were in 2023 &amp;#8230; and 2020). Thanks to the authors for reviving the fun.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Please keep staying safe and healthy, and keep up the good work! Even after week 63 of hopefully only 209.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;~librasteve&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Post image attribution: Eddie Leslie from Lancashire, CC BY-SA 2.0 https://creativecommons.org/licenses/by-sa/2.0, via Wikimedia Commons Whateverables Corner This week sees the release of 3 (yes, 3) new Whateverables. The Whateverables are a collection of IRC bots primarily useful for Raku developers. They are written in Raku and are based on IRC::Client. Many of the use cases […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakudoweekly.blog/?p=8765</id>
    <published>2026-04-13T17:59:27Z</published>
    <updated>2026-04-13T17:59:27Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>2026.14 Trim Flip-flops</title>
    <link rel="alternate" href="https://rakudoweekly.blog/2026/04/06/2026-14-trim-flip-flops/" type="text/html"/>
    <content type="html">
&lt;h3 class="wp-block-heading"&gt;Habere&amp;#8217;s Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Habere-et-Dispertire&lt;/em&gt; has &lt;a href="https://github.com/habere-et-dispertire/tldr/blob/main/pages/common/raku.md"&gt;shared&lt;/a&gt; some new notes on using the &lt;code&gt;raku&lt;/code&gt; command:&lt;/p&gt;



&lt;div class="wp-block-jetpack-markdown"&gt;&lt;ul&gt;
&lt;li&gt;Remove leading and trailing whitespace:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;raku -ne &amp;quot;put .trim&amp;quot; {{/path/to/file}}&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract lines between START and STOP markers (inclusive)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;raku -ne '.put if &amp;quot;START&amp;quot; ff &amp;quot;STOP&amp;quot;' {{/path/to/file}}&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract lines between START and STOP markers (exclusive)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;raku -ne '.put if &amp;quot;START&amp;quot; ^ff^ &amp;quot;STOP&amp;quot;' {{/path/to/file}}&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;h3 class="wp-block-heading"&gt;TPRC Submit your Talk&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Don’t Miss the Perl and Raku Conference 2026 in Greenville, SC&lt;br&gt;SAVE THE DATES! Friday through Sunday, June 26-28&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Registration is open: &lt;a href="https://tprc.us/tprc-2026-gsp"&gt;https://tprc.us/tprc-2026-gsp&lt;/a&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Weekly Challenge&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-368"&gt;Weekly Challenge #368&lt;/a&gt; is available for your entertainment.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Raku Tips &amp;#8216;n Tricks&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;This week, my eye was caught by what looked like a simple question on the IRC (Discord) channels:&lt;/p&gt;



&lt;div style="font-weight: 500 .nohighlights { background" class="raku-code"&gt;&lt;div&gt;&lt;pre class="nohighlights" style="font-size: 1em;font-family: monospace"&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;(&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%a&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@b&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%c&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@d&lt;/span&gt;)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;(1&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;2).&lt;span style="color: #489fdc" class="rainbow-routine"&gt;map&lt;/span&gt;({&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;|&lt;/span&gt;({&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #369ec6" class="rainbow-string"&gt;a&lt;/span&gt;&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&amp;gt;&lt;/span&gt;&amp;nbsp;1}&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;[1])&amp;nbsp;});&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;




&lt;p class="wp-block-paragraph"&gt;Why does this seeming straightforward list assignment with &lt;code&gt;=&lt;/code&gt; (see &lt;a href="https://docs.raku.org/language/variables#Item_and_list_assignment"&gt;docs&lt;/a&gt;) cause an error?&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;Odd number of elements found where hash initializer expected:&lt;/div&gt;&lt;div class="cm-line"&gt;Found 5 (implicit) elements: ...&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s tease that apart, say we make the LHS just a single Array &lt;code&gt;@b&lt;/code&gt; and then a single Hash &lt;code&gt;%a&lt;/code&gt;&lt;/p&gt;



&lt;div style="font-weight: 500 .nohighlights { background" class="raku-code"&gt;&lt;div&gt;&lt;pre class="nohighlights" style="font-size: 1em;font-family: monospace"&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@b&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;(1&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;2).&lt;span style="color: #489fdc" class="rainbow-routine"&gt;map&lt;/span&gt;({&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;|&lt;/span&gt;({&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #369ec6" class="rainbow-string"&gt;a&lt;/span&gt;&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&amp;gt;&lt;/span&gt;&amp;nbsp;1}&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;[1])&amp;nbsp;});&amp;nbsp;&lt;br&gt;&lt;span style="color: #4aa36c" class="rainbow-comment"&gt;#OUTPUT say @b; #[&amp;#123;a =&amp;gt; 1&amp;#125; [1] &amp;#123;a =&amp;gt; 1&amp;#125; [1]]&lt;br&gt;&lt;/span&gt;&lt;br&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%a&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;(1&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;2).&lt;span style="color: #489fdc" class="rainbow-routine"&gt;map&lt;/span&gt;({&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;|&lt;/span&gt;({&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #369ec6" class="rainbow-string"&gt;a&lt;/span&gt;&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&amp;gt;&lt;/span&gt;&amp;nbsp;1}&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;[1])&amp;nbsp;});&lt;br&gt;&lt;span style="color: #4aa36c" class="rainbow-comment"&gt;#ERROR&lt;br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;




&lt;p class="wp-block-paragraph"&gt;The docs say that list assignment is governed by the LHS &amp;#8211; an Array will take all the RHS elements. We can surmise that a Hash will take all the RHS elements &amp;#8211; even splitting key, values &amp;#8211; and translate them into &lt;code&gt;key =&amp;gt; value&lt;/code&gt; pairs. Thus the error if presented with an odd number in total.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Despite this frustration, Raku has two ways to make this work:&lt;/p&gt;



&lt;div style="font-weight: 500 .nohighlights { background" class="raku-code"&gt;&lt;div&gt;&lt;pre class="nohighlights" style="font-size: 1em;font-family: monospace"&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;(&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%a&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@b&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%c&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@d&lt;/span&gt;)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;Z&lt;/span&gt;=&amp;nbsp;(1&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;2).&lt;span style="color: #489fdc" class="rainbow-routine"&gt;map&lt;/span&gt;({&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;|&lt;/span&gt;({&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #369ec6" class="rainbow-string"&gt;a&lt;/span&gt;&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&amp;gt;&lt;/span&gt;&amp;nbsp;1}&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;[1])&amp;nbsp;});&lt;br&gt;&lt;span style="color: #4aa36c" class="rainbow-comment"&gt;#-or-&lt;br&gt;&lt;/span&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;(&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%a&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@b&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%c&lt;/span&gt;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@d&lt;/span&gt;)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:=&lt;/span&gt;&amp;nbsp;(1&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;2).&lt;span style="color: #489fdc" class="rainbow-routine"&gt;map&lt;/span&gt;({&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;|&lt;/span&gt;({&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #369ec6" class="rainbow-string"&gt;a&lt;/span&gt;&lt;span style="color: #1d90d2" class="rainbow-string_delimiter"&gt;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&amp;gt;&lt;/span&gt;&amp;nbsp;1}&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;[1])&amp;nbsp;});&lt;br&gt;&lt;br&gt;&lt;span style="color: #489fdc" class="rainbow-routine"&gt;say&lt;/span&gt;&amp;nbsp;{&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%a&lt;/span&gt;,&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@b&lt;/span&gt;,&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #00a693" class="rainbow-name_hash"&gt;%c&lt;/span&gt;,&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;:&lt;/span&gt;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@d&lt;/span&gt;}&lt;br&gt;&lt;span style="color: #4aa36c" class="rainbow-comment"&gt;#OUTPUT &amp;#123;a =&amp;gt; &amp;#123;a =&amp;gt; 1&amp;#125;, b =&amp;gt; [1], c =&amp;gt; &amp;#123;a =&amp;gt; 1&amp;#125;, d =&amp;gt; [1]&amp;#125;&lt;br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;



&lt;p class="wp-block-paragraph"&gt;You can use binding &lt;code&gt;:=&lt;/code&gt; instead and since the LHS and the RHS have the same data structure this will work. Or you can combine &lt;code&gt;Z&lt;/code&gt; (the &lt;em&gt;zip&lt;/em&gt; metaoperator) with &lt;code&gt;=&lt;/code&gt; (item assignment), like this:&lt;/p&gt;



&lt;div style="font-weight: 500 .nohighlights { background" class="raku-code"&gt;&lt;div&gt;&lt;pre class="nohighlights" style="font-size: 1em;font-family: monospace"&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;(a&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;b&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;c)&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;Z&lt;/span&gt;=&amp;nbsp;(a&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;b&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;,&lt;/span&gt;&amp;nbsp;c);&lt;br&gt;&lt;span style="color: #4aa36c" class="rainbow-comment"&gt;#turns that assignment into boring &lt;br&gt;&lt;/span&gt;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;a&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@x&lt;/span&gt;[0];&amp;nbsp;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;b&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@x&lt;/span&gt;[1];&amp;nbsp;&lt;span style="color: #008c7e" class="rainbow-keyword"&gt;my&lt;/span&gt;&amp;nbsp;c&amp;nbsp;&lt;span style="color: #1ca24f" class="rainbow-operator"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color: #B01030" class="rainbow-name_array"&gt;@x&lt;/span&gt;[2]&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;




&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Your contribution is welcome, please make a gist and share via the #raku channel on IRC or Discord.&lt;/em&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Questions About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/rakulang/comments/1s8lotu/type_inference/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button"&gt;I asked about type inference in Raku about seven years ago&lt;/a&gt; by &lt;em&gt;dharmatech&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Comments About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://fosstodon.org/@smokemachine/116355953497672920"&gt;I’d like opinions on this project to facilitate writing EventSourcing&lt;/a&gt; by &lt;em&gt;SmokeMachine&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://mastodon.social/@lizmat/116336094399286998"&gt;feels like a special container class in #rakulang should be possible&lt;/a&gt; by &lt;em&gt;lizmat&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://lobste.rs/s/sazeyn/don_t_trust_software_verify_it#c_wmfw6v"&gt;Obligatory Raku: &lt;code&gt;say 𐄊+ ᮳;&lt;/code&gt;&lt;/a&gt; by &lt;em&gt;hwayne&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;div&gt;
&lt;h3&gt;New Doc &amp;amp; Web Pull Requests&lt;/h3&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/311"&gt;add raku CCR panel&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3 class="wp-block-heading"&gt;New Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/DSL::English::EpidemiologyModelingWorkflows"&gt;DSL::English::EpidemiologyModelingWorkflows&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/DSL::English::FoodPreparationWorkflows"&gt;DSL::English::FoodPreparationWorkflows&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/DSL::Entity::Jobs"&gt;DSL::Entity::Jobs&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/Math::GameTheory"&gt;Math::GameTheory&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/DSL::Entity::Foods"&gt;DSL::Entity::Foods&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/DSL::English::DataAcquisitionWorkflows"&gt;DSL::English::DataAcquisitionWorkflows&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/DSL::Translators"&gt;DSL::Translators&lt;/a&gt; by 
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Updated Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:ohmycloudy/Recipe::Parser"&gt;Recipe::Parser&lt;/a&gt; by
&lt;em&gt;ohmycloudy&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:martimm/GnomeTools"&gt;GnomeTools&lt;/a&gt; by
&lt;em&gt;Marcel Timmerman&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:librasteve/Physics::Unit"&gt;Physics::Unit&lt;/a&gt;,
&lt;a href="https://raku.land/zef:librasteve/Physics::Measure"&gt;Physics::Measure&lt;/a&gt;,
&lt;a href="https://raku.land/zef:librasteve/App::Crag"&gt;App::Crag&lt;/a&gt; by
&lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:tony-o/Data::Dump"&gt;Data::Dump&lt;/a&gt; by
&lt;em&gt;Tony O&amp;#039;Dell&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:lizmat/path-utils"&gt;path-utils&lt;/a&gt; by
&lt;em&gt;Elizabeth Mattijsen&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/github:nige123/jmp"&gt;jmp&lt;/a&gt; by
&lt;em&gt;github:nige123&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:raku-community-modules/GD::Raw"&gt;GD::Raw&lt;/a&gt; by
&lt;em&gt;Various Artistes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:sp1983/Sparrow6"&gt;Sparrow6&lt;/a&gt;,
&lt;a href="https://raku.land/zef:sp1983/Sparky"&gt;Sparky&lt;/a&gt; by
&lt;em&gt;zef:sp1983&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:Zer0-Tolerance/MongoDB::Fast"&gt;MongoDB::Fast&lt;/a&gt; by
&lt;em&gt;Zer0-Tolerance&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/Data::TypeSystem"&gt;Data::TypeSystem&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/LLM::Graph"&gt;LLM::Graph&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/Data::Translators"&gt;Data::Translators&lt;/a&gt; by
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:dwarring/Font::FreeType"&gt;Font::FreeType&lt;/a&gt;,
&lt;a href="https://raku.land/zef:dwarring/PDF::Class"&gt;PDF::Class&lt;/a&gt;,
&lt;a href="https://raku.land/zef:dwarring/CSS::Stylesheet"&gt;CSS::Stylesheet&lt;/a&gt; by
&lt;em&gt;David Warring&lt;/em&gt;&lt;/li&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://github.com/lizmat/articles/blob/main/weekly-2022.51.md#winding-down"&gt;&lt;/a&gt;Winding down&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;A quiet-ish week this week. Kudos to &lt;em&gt;Anton&lt;/em&gt; for his productive spurt on the module front. Happy Easter to those who celebrate.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Please keep staying safe and healthy, and keep up the good work! Even after week 62 of hopefully only 209.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;~librasteve&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Habere’s Corner Habere-et-Dispertire has shared some new notes on using the raku command: TPRC Submit your Talk Don’t Miss the Perl and Raku Conference 2026 in Greenville, SCSAVE THE DATES! Friday through Sunday, June 26-28 Registration is open: https://tprc.us/tprc-2026-gsp Weekly Challenge Weekly Challenge #368 is available for your entertainment. Raku Tips ‘n Tricks This week, […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakudoweekly.blog/?p=8741</id>
    <published>2026-04-06T18:45:19Z</published>
    <updated>2026-04-06T18:45:19Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>2026.13 Release #191</title>
    <link rel="alternate" href="https://rakudoweekly.blog/2026/03/31/2026-13-release-191/" type="text/html"/>
    <content type="html">
&lt;p class="wp-block-paragraph"&gt;On behalf of the Rakudo development team, I’m happy to announce the March 2026 release of Rakudo #191. Rakudo is an implementation of the Raku language.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The source tarball for this release is available from &lt;a href="https://rakudo.org/files/rakudo."&gt;https://rakudo.org/files/rakudo.&lt;/a&gt; Pre-compiled archives will be available shortly.&lt;/p&gt;



&lt;h4 class="wp-block-heading"&gt;New in 2026.03:&lt;/h4&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Improvements:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Update to libtommath 1.3.0 [28d9a006]&lt;/li&gt;



&lt;li&gt;Update to mimalloc v2.2.7 [7ab77078]&lt;/li&gt;



&lt;li&gt;Provide better error when trying to decode too large blobs [06f16f6d]&lt;/li&gt;



&lt;li&gt;Deprecate &amp;#8220;-&amp;#8221; as an STDIN/STDOUT indicator in 6.d [3e6406f5][d9f66ef1]&lt;/li&gt;



&lt;li&gt;Deprecate Perl.new [baed6071]&lt;/li&gt;



&lt;li&gt;Optimizations [ae4c136d][5c93e18b][babc6ca4][699cbac2][ac2c4cb4]&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Fixes:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;In methods of Cool that call methods of Str, coerce Cool parameters to the correct types [fffdb91f]&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Additions:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Add CallFrame.language-revision [11e48594]&lt;/li&gt;



&lt;li&gt;Add Rakudo::Internals.client-callframe method [17b9dc45]&lt;/li&gt;



&lt;li&gt;Add Rakudo::Internals.client-language-revision [472105cd]&lt;/li&gt;



&lt;li&gt;Add single named arg candidate to subtest [cfd44496]&lt;/li&gt;



&lt;li&gt;RakuAST: [6d2fa67e][ddd5a97c][50276894][1cd333d8][d76960ba][2efcd855][400c61b9] [d13b7ab6][7a61872f][5697a5ac][759f8ba8][4e007063][fbe5a50b][8b0d6d23] [bc6c03c7][7bb73918][c318ac31][74da84b0][107ed65b][2c9345e8][fe2e46e3]&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Internal:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Make all core constants &amp;#8220;my&amp;#8221; scoped [7fc93d52]&lt;/li&gt;



&lt;li&gt;Update IO::Path.slurp [a77416b8][a97c7a33][af30c7be]&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;The following people contributed to this release:&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Elizabeth Mattijsen, Will Coleda, Daniel Green, Justin DeVuyst, David Schultz, Eric Forste, Márton Polgár, Patrick Böker, Richard Hainsworth, ab5tract&lt;/em&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;TPRC Submit your Talk&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Don’t Miss the Perl and Raku Conference 2026 in Greenville, SC&lt;br&gt;SAVE THE DATES! Friday through Sunday, June 26-28&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Registration is open: &lt;a href="https://tprc.us/tprc-2026-gsp"&gt;https://tprc.us/tprc-2026-gsp&lt;/a&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Zoffix&amp;#8217;s Corner (of old)&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;The Raku Programming Language Collect, Conserve and Remaster Project &amp;#8211; &lt;em&gt;lizmat&lt;/em&gt; has remastered&amp;#8230; &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://raku.github.io/CCR/Remaster/Zoffix%20Znet/On-Troll-Hugging-Hole-Digging-and-Improving-Open-Source-Communities.html"&gt;On Troll Hugging, Hole Digging, and Improving Open Source Communities&lt;/a&gt;&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://raku.github.io/CCR/Remaster/Zoffix%20Znet/digging2-bad-hole.png" alt="" /&gt;&lt;/figure&gt;



&lt;h3 class="wp-block-heading"&gt;Timo&amp;#8217;s Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://github.com/MoarVM/MoarVM/pull/1996"&gt;Support for fuzzing moar itself with AFL&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://peoplemaking.games/@timotimo/116315002606439158"&gt;Dipped my toes&lt;/a&gt; in #AFLplusplus over the weekend was a kinda nice distraction / pastime.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Got #moarvm (language runtime for #rakulang) its first fuzzing target that exercises the streaming decoder system which is what you would use when reading strings (rather than bytes) with some encoding from a streaming source like the output of a process you&amp;#8217;re running.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Anton&amp;#8217;s Corner&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;If you are in a generous mood and would like to see WWW::Anthropic as a Raku module, then please take note:&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;BTW, if someone is willing to &amp;#8220;donate&amp;#8221; Anthropoc API key to me &amp;#8212; for a day or two &amp;#8212; I can implement &amp;#8220;WWW::Anthropic&amp;#8221;&lt;/em&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Anton is on the Discord / IRC bridge for privmsg purposes.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Steve&amp;#8217;s Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.reddit.com/r/CLI/comments/1s7wive/cragcli_command_line_calculator_examples/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button"&gt;CragCLI &amp;#8211; Command Line Calculator &amp;#8211; Examples&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I recently shared my fun project here (&lt;a href="https://www.reddit.com/r/CLI/"&gt;https://www.reddit.com/r/CLI/&lt;/a&gt;). Someone commented &amp;#8220;OK it looks cool, but what can I do with it&amp;#8221;, so now sharing an example (4 gifs) to demonstrate the potential.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Weekly Challenge&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-367"&gt;Weekly Challenge #367&lt;/a&gt; is available for your entertainment.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Raku Tips &amp;#8216;n Tricks&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;This week, Will Coleda amuses and informs us with their &lt;a href="https://raku.land/zef:coke/App::Unicode::Mangle"&gt;App::Unicode::Mangle&lt;/a&gt; module. Despite the obvious -Ofun applications, this is a great inspiration for folks who are interested in how to apply unicode props.&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code class="language-perl"&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;circle&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;#rakulang&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-comment"&gt;#ⓡⓐⓚⓤⓛⓐⓝⓖ&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;invert&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;Hello, github!&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;¡&lt;span class="tok-meta"&gt;qu&lt;/span&gt;ɥʇıƃ ,&lt;span class="tok-meta"&gt;o&lt;/span&gt;ʃʃǝ&lt;span class="tok-meta"&gt;H&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;bold&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;A bird, a plane.&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;𝐀 𝐛𝐢𝐫𝐝, 𝐚 𝐩𝐥𝐚𝐧𝐞&lt;span class="tok-operator"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;paren&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;lisplike&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;⒧⒤⒮⒫⒧⒤⒦⒠&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;combo&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;combo breaker&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;c&lt;/span&gt;̩͘&lt;span class="tok-meta"&gt;o&lt;/span&gt;̍ͧ&lt;span class="tok-meta"&gt;m&lt;/span&gt;ͮ͠&lt;span class="tok-meta"&gt;b&lt;/span&gt;̄͋&lt;span class="tok-meta"&gt;o&lt;/span&gt;̸̫ ̣͚&lt;span class="tok-meta"&gt;b&lt;/span&gt;͠ͅř̗ẻ͔&lt;span class="tok-meta"&gt;a&lt;/span&gt;ͪ͢&lt;span class="tok-meta"&gt;k&lt;/span&gt;̥̀&lt;span class="tok-meta"&gt;e&lt;/span&gt;̒͋&lt;span class="tok-meta"&gt;r&lt;/span&gt;͎̦&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;italic&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;The Telltale Heart&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;𝘛𝘩𝘦 𝘛𝘦𝘭𝘭𝘵𝘢𝘭𝘦 𝘏𝘦𝘢𝘳𝘵&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;square&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;Presenting&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;🄿 🅁 🄴 🅂 🄴 🄽 🅃 🄸 🄽 🄶&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;nsquare&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;A little boxy&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&amp;#x1f170;   🅻 🅸 🆃 🆃 🅻 🅴   &amp;#x1f171; &amp;#x1f17e; &amp;#x274e; 🆈&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$ &lt;span class="tok-meta"&gt;uni&lt;/span&gt;&lt;span class="tok-operator"&gt;-&lt;/span&gt;&lt;span class="tok-meta"&gt;mangler&lt;/span&gt; &lt;span class="tok-operator"&gt;--&lt;/span&gt;&lt;span class="tok-meta"&gt;random&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;Happy Birthday!&amp;apos;&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;Ⓗ⒜ⓟ𝐩𝐲 𐐒⒤𝐫⒯⒣&lt;span class="tok-meta"&gt;p&lt;/span&gt;ɐ⒴¡&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Your contribution is welcome, please make a gist and share via the #raku channel on IRC or Discord.&lt;/em&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Questions About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/79915186/does-raku-have-an-sdk-related-to-anthropic"&gt;Does Raku have an SDK related to Anthropic?&lt;/a&gt; by &lt;em&gt;ohmycloudy&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Comments About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://peoplemaking.games/@timotimo/116315002606439158"&gt;Got #moarvm (language runtime for #rakulang) its first fuzzing target&lt;/a&gt; by &lt;em&gt;timotimo&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://mastodon.social/@peateasea/116295646553992658"&gt;28th edition of the German Perl/Raku Workshop &amp;#8230; rough notes&lt;/a&gt; by &lt;em&gt;Paul Cochrane&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=47477525#47506462"&gt;I&amp;#8217;ve recently been exposed to the Raku language, and it strikes me as sort of a … dynamic version of Swift? It&amp;#8217;s jammed full of functionality, with an emphasis on being able to design syntax a-la DSL.&lt;/a&gt; by &lt;em&gt;leecommamichael&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;div&gt;
&lt;h3&gt;New Doc &amp;amp; Web Pull Requests&lt;/h3&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/311"&gt;add raku CCR panel&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/310"&gt;Fix IRC chat link&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/308"&gt;redo ofun redirects&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/307"&gt;re add fun, ofun redirects&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/doc/pull/4797"&gt;Puli Proposal for revision of Instant class documentation&lt;/a&gt;
&lt;em&gt;Ralph Mellor&lt;/em&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3 class="wp-block-heading"&gt;Updated Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:FCO/IdClass"&gt;IdClass&lt;/a&gt; by 
&lt;em&gt;Fernando Correa de Oliveira&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:kuerbis/Term::TablePrint"&gt;Term::TablePrint&lt;/a&gt; by 
&lt;em&gt;Matthäus Kiem&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/github:nige123/jmp"&gt;jmp&lt;/a&gt; by 
&lt;em&gt;github:nige123&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:japhb/Terminal::Tests"&gt;Terminal::Tests&lt;/a&gt;,
&lt;a href="https://raku.land/zef:japhb/Terminal::Capabilities"&gt;Terminal::Capabilities&lt;/a&gt; by 
&lt;em&gt;Geoffrey Broadwell&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:dwarring/PDF::Class"&gt;PDF::Class&lt;/a&gt;,
&lt;a href="https://raku.land/zef:dwarring/CSS::Stylesheet"&gt;CSS::Stylesheet&lt;/a&gt; by 
&lt;em&gt;David Warring&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/Text::Calendar"&gt;Text::Calendar&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/Data::Translators"&gt;Data::Translators&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/LaTeX::Grammar"&gt;LaTeX::Grammar&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/CortexJS"&gt;CortexJS&lt;/a&gt; by 
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:librasteve/App::Crag"&gt;App::Crag&lt;/a&gt; by 
&lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:Zer0-Tolerance/Net::Netmask::Fast"&gt;Net::Netmask::Fast&lt;/a&gt;,
&lt;a href="https://raku.land/zef:Zer0-Tolerance/MongoDB::Fast"&gt;MongoDB::Fast&lt;/a&gt; by 
&lt;em&gt;Zer0-Tolerance&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://github.com/lizmat/articles/blob/main/weekly-2022.51.md#winding-down"&gt;&lt;/a&gt;Winding down&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Congrats to the core team for maintaining their steady release tempo. Great to see the RakuAST mineshaft is getting a little deeper each time.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Zoffix&amp;#8217;s post on OSS communities was a foundational read for me back in the day. Thank&amp;#8217;s to lizmat and her &lt;a href="https://github.com/Raku/CCR"&gt;CCR&lt;/a&gt; project for remastering this to a usable state. Please do reach out and help on this if you can.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Please keep staying safe and healthy, and keep up the good work! Even after week 61 of hopefully only 209.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;~librasteve&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">On behalf of the Rakudo development team, I’m happy to announce the March 2026 release of Rakudo #191. Rakudo is an implementation of the Raku language. The source tarball for this release is available from https://rakudo.org/files/rakudo. Pre-compiled archives will be available shortly. New in 2026.03: Improvements: Fixes: Additions: Internal: The following people contributed to this […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakudoweekly.blog/?p=8715</id>
    <published>2026-03-31T11:36:41Z</published>
    <updated>2026-03-31T11:36:41Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title> Rakudo compiler, Release #191 (2026.03)</title>
    <link rel="alternate" href="https://rakudo.org/post/announce-rakudo-release-2026.03" type="text/html"/>
    <id>https://rakudo.org/post/announce-rakudo-release-2026.03</id>
    <published>2026-03-28T00:00:00Z</published>
    <updated>2026-03-28T00:00:00Z</updated>
  </entry>
  <entry>
    <title>2026.12 Ich bin ein Berliner</title>
    <link rel="alternate" href="https://rakudoweekly.blog/2026/03/23/2026-12-ich-bin-ein-berliner/" type="text/html"/>
    <content type="html">
&lt;h3 class="wp-block-heading"&gt;TPRC Talk Submission Deadline Extended&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Breaking news: &lt;a href="https://news.perlfoundation.org/post/tprc-2026-talk-submission-deadline-extended"&gt;TPRC Talk Submission Deadline extended to April 21, 2026.&lt;/a&gt; Many thanks to the organisers for heeding our call for more time.&lt;/p&gt;



&lt;blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"&gt;
&lt;p class="wp-block-paragraph"&gt;We are re-opening the talk submissions for TPRC with a new deadline of April 21, 2026. &amp;nbsp;&amp;nbsp;Please submit your 20 minute talks, and 50 minute talks at &lt;a href="https://tprc.us/" rel="nofollow"&gt;https://tprc.us/&lt;/a&gt;. &amp;nbsp;Let us know if you need help with your submission or your talk development, because we have mentors who can listen to your ideas and guide you.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;We are also taking submissions for interactive sessions.&amp;nbsp; These are sessions that have a theme, but invite maximum audience participation; sessions which take advantage of the gathering of community members that have a wide range of experience and ideas to share.&amp;nbsp; You would introduce the theme and moderate the session.&amp;nbsp; If you have ideas for interactive sessions, but don’t want to moderate them yourself, please go to our wiki to enter your ideas, and maybe someone else will pick up the ball!&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p class="wp-block-paragraph"&gt;Don’t Miss the Perl and Raku Conference 2026 in Greenville, SC&lt;br&gt;SAVE THE DATES! Friday through Sunday, June 26-28&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Registration is open: &lt;a href="https://tprc.us/tprc-2026-gsp"&gt;https://tprc.us/tprc-2026-gsp&lt;/a&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Last Week German Perl/Raku Workshop&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;28th German Perl/Raku &lt;a href="https://act.yapc.eu/gpw2026/index.html"&gt;Workshop&lt;/a&gt; (16th-18th March 2026 in Berlin) took place last week.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Here are some photos from the pre-conference social:&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img width="1018" height="964" data-attachment-id="8693" data-permalink="https://rakudoweekly.blog/2026/03/23/2026-12-ich-bin-ein-berliner/screenshot-2026-03-23-at-17-58-35/" data-orig-file="https://rakudoweekly.blog/wp-content/uploads/2026/03/screenshot-2026-03-23-at-17.58.35.png" data-orig-size="1018,964" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;alt&amp;quot;:&amp;quot;&amp;quot;}" data-image-title="Screenshot 2026-03-23 at 17.58.35" data-image-description="" data-image-caption="" data-large-file="https://rakudoweekly.blog/wp-content/uploads/2026/03/screenshot-2026-03-23-at-17.58.35.png?w=1018" src="https://rakudoweekly.blog/wp-content/uploads/2026/03/screenshot-2026-03-23-at-17.58.35.png?w=1018" alt="" class="wp-image-8693" srcset="https://rakudoweekly.blog/wp-content/uploads/2026/03/screenshot-2026-03-23-at-17.58.35.png 1018w, https://rakudoweekly.blog/wp-content/uploads/2026/03/screenshot-2026-03-23-at-17.58.35.png?w=150 150w, https://rakudoweekly.blog/wp-content/uploads/2026/03/screenshot-2026-03-23-at-17.58.35.png?w=300 300w, https://rakudoweekly.blog/wp-content/uploads/2026/03/screenshot-2026-03-23-at-17.58.35.png?w=768 768w" sizes="(max-width: 1018px) 100vw, 1018px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;I look forward to seeing the videos and presentations, meantime &lt;a href="https://act.yapc.eu/gpw2026/talks"&gt;here&lt;/a&gt; is the list to whet your appetite.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Marton&amp;#8217;s Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Raku community(?) in 2026 &amp;#8211; how my permanent ban came to be &amp;#8211; Marton Polgar&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://programming.dev/post/47337716"&gt;https://programming.dev/post/47337716&lt;/a&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Anton&amp;#8217;s Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.youtube.com/watch?v=du3tbWqdP-c"&gt;Equinox 2026&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;This presentation shows how using Raku&amp;#8217;s interactivity and inter-op packages scientific plots and artistic images can be created and generated.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Gérald&amp;#8217;s Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;rakulang goes post-quantum! I added a &lt;em&gt;toy&lt;/em&gt; implementation of the ML-DSA digital signature algorithm to the Obscure #cryptography library &lt;a href="https://github.com/gdncc/Obscure" rel="nofollow"&gt;https://github.com/gdncc/Obscure&lt;/a&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://github.com/gdncc/Obscure"&gt;Obscure: a Raku Programming Language Cryptography Playground&lt;/a&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Weekly Challenge&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-366"&gt;Weekly Challenge #366&lt;/a&gt; is available for your amusement.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Raku Tips &amp;#8216;n Tricks&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;One of the hidden gems of the Raku &lt;a href="https://docs.raku.org/"&gt;docs&lt;/a&gt; is the generated typegraph. Here is an example, the Allomorph &lt;a href="https://docs.raku.org/type/Allomorph#typegraphrelations"&gt;type graph&lt;/a&gt;:&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://rakujourney.wordpress.com/wp-content/uploads/2023/12/screenshot-2023-12-21-at-15.30.18.png" alt="" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;You can find these at the end of the docs page for most classes (blue &amp;#8211; &lt;code&gt;does Role&lt;/code&gt;, black &amp;#8211; &lt;code&gt;is Class&lt;/code&gt;).&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s say you have gone to the trouble of writing something like this, and you are still relatively new to raku:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code class="language-perl"&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-keyword"&gt;sub&lt;/span&gt; &lt;span class="tok-meta"&gt;dub&lt;/span&gt;(&lt;span class="tok-meta"&gt;Int&lt;/span&gt; &lt;span class="tok-variableName"&gt;$x&lt;/span&gt;) { &lt;span class="tok-variableName"&gt;$x&lt;/span&gt; &lt;span class="tok-operator"&gt;*&lt;/span&gt; &lt;span class="tok-number"&gt;2&lt;/span&gt; }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;dub&lt;/span&gt; &lt;span class="tok-number"&gt;2&lt;/span&gt;;   &lt;span class="tok-comment"&gt;#4&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;dub&lt;/span&gt; &lt;span class="tok-string"&gt;&amp;apos;2&amp;apos;&lt;/span&gt;; &lt;span class="tok-comment"&gt;#Calling dub(Str) will never work with declared signature (Int $x)&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;dub&lt;/span&gt; &lt;span class="tok-operator"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tok-number"&gt;2&lt;/span&gt;&lt;span class="tok-operator"&gt;&amp;gt;&lt;/span&gt;; &lt;span class="tok-comment"&gt;#4&lt;/span&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;dd&lt;/span&gt; &lt;span class="tok-operator"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tok-number"&gt;2&lt;/span&gt;&lt;span class="tok-operator"&gt;&amp;gt;&lt;/span&gt;;  &lt;span class="tok-comment"&gt;#IntStr.new(2, &amp;quot;2&amp;quot;)&lt;/span&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;A skim read of the docs, suggests that &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; angle brackets are for &lt;a href="https://docs.raku.org/language/quoting#Word_quoting:_%3C_%3E"&gt;word quoting&lt;/a&gt;, and it is easy to get the idea that they would make &lt;code&gt;&amp;lt;2&amp;gt;&lt;/code&gt; into &lt;code&gt;'2'&lt;/code&gt;. And so it is, at first, surprising that &lt;code&gt;dub &amp;lt;2&amp;gt;&lt;/code&gt; succeeds in passing an Int type check.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Actually since you have all now read Lizmats great advent post on &lt;a href="https://raku-advent.blog/2023/12/14/day-14-the-magic-of-q-part-2/"&gt;Q &lt;/a&gt;&lt;a href="https://raku-advent.blog/2023/12/10/day-10-the-magic-of-q/"&gt;constructs&lt;/a&gt;, you will know that &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; calls the &lt;a href="https://raku-advent.blog/2023/12/10/day-10-the-magic-of-q/"&gt;val()&lt;/a&gt; function on each word. And that makes an &lt;strong&gt;Allomorph&lt;/strong&gt; if the word can be construed as a string with a value. In this case, an &lt;strong&gt;IntStr&lt;/strong&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Allomorph classes should be considered a common raku scenario. If you are thinking &amp;#8220;I checked for Int and I got something that is not an Int (but inherits from Int)&amp;#8221;, then this is a general misunderstanding about how type checking and class inheritance works and is not limited to Allomorphs.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Consider this code:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code class="language-perl"&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;class&lt;/span&gt; &lt;span class="tok-meta"&gt;Animal&lt;/span&gt; {} &lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;class&lt;/span&gt; &lt;span class="tok-meta"&gt;Horse&lt;/span&gt; &lt;span class="tok-meta"&gt;is&lt;/span&gt; &lt;span class="tok-meta"&gt;Animal&lt;/span&gt; {}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-meta"&gt;class&lt;/span&gt; &lt;span class="tok-meta"&gt;Human&lt;/span&gt; &lt;span class="tok-meta"&gt;is&lt;/span&gt; &lt;span class="tok-meta"&gt;Animal&lt;/span&gt; {}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-keyword"&gt;sub&lt;/span&gt; &lt;span class="tok-meta"&gt;cantread&lt;/span&gt;(&lt;span class="tok-meta"&gt;Animal&lt;/span&gt; &lt;span class="tok-variableName"&gt;$a&lt;/span&gt;) { &lt;span class="tok-string"&gt;&amp;quot;{$a.^name}s can&amp;apos;t read&amp;quot;&lt;/span&gt; }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-variableName tok-definition"&gt;my&lt;/span&gt; &lt;span class="tok-variableName"&gt;$h&lt;/span&gt; &lt;span class="tok-operator"&gt;=&lt;/span&gt; &lt;span class="tok-meta"&gt;Human&lt;/span&gt;&lt;span class="tok-operator"&gt;.&lt;/span&gt;&lt;span class="tok-keyword"&gt;new&lt;/span&gt;;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;span class="tok-keyword"&gt;say&lt;/span&gt; &lt;span class="tok-meta"&gt;cantread&lt;/span&gt; &lt;span class="tok-variableName"&gt;$h&lt;/span&gt;; &lt;span class="tok-comment"&gt;#Humans can&amp;apos;t read&lt;/span&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;No Allomorphs in sight, but it does the &amp;#8220;surprising&amp;#8221; thing of letting a Human pass the Animal type check.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Your contribution is welcome, please make a gist and share via the #raku channel on IRC or Discord.&lt;/em&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Comments About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://programming.dev/post/47337716/22768048"&gt;That was a crazy read, Nemokosch is truly insufferable.&lt;/a&gt; by &lt;em&gt;YarrMatey&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=47448328#47449404"&gt;the XLibre folks seem to be taking the Perl5 path, and hoping Wayland is Raku&lt;/a&gt; &lt;em&gt;by __d&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;div&gt;
&lt;h3&gt;New Problem Solving Issues&lt;/h3&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/problem-solving/issues/517"&gt;Raku.org -Ofun Panel Quality Concerns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/problem-solving/issues/516"&gt;Consider &amp;#096;&amp;lt;-1/-0&amp;gt;.sign #-1&amp;#096; Incorrect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/problem-solving/issues/515"&gt;Implement IEEE P754 Divide By Zero Rules &amp;amp; $*DBZ-Suppress Option&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;New Doc &amp;amp; Web Pull Requests&lt;/h3&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/304"&gt;Logos&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/302"&gt;add -Ofun &amp;amp; redirect&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3 class="wp-block-heading"&gt;New Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/CortexJS"&gt;CortexJS&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/LaTeX::Grammar"&gt;LaTeX::Grammar&lt;/a&gt; by
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:FCO/IdClass"&gt;IdClass&lt;/a&gt; by
&lt;em&gt;Fernando Correa de Oliveira&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Updated Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:bduggan/App::samaki"&gt;App::samaki&lt;/a&gt;,
&lt;a href="https://raku.land/zef:bduggan/Duckie"&gt;Duckie&lt;/a&gt; by 
&lt;em&gt;Brian Duggan&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:sp1983/Sparrowdo"&gt;Sparrowdo&lt;/a&gt;,
&lt;a href="https://raku.land/zef:sp1983/Sparrow6"&gt;Sparrow6&lt;/a&gt; by 
&lt;em&gt;zef:sp1983&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:dwarring/CSS::Properties"&gt;CSS::Properties&lt;/a&gt;,
&lt;a href="https://raku.land/zef:dwarring/CSS::Module"&gt;CSS::Module&lt;/a&gt;,
&lt;a href="https://raku.land/zef:dwarring/CSS::Writer"&gt;CSS::Writer&lt;/a&gt; by 
&lt;em&gt;David Warring&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/WWW::OpenAI"&gt;WWW::OpenAI&lt;/a&gt; by
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:librasteve/Physics::Measure"&gt;Physics::Measure&lt;/a&gt;,
&lt;a href="https://raku.land/zef:librasteve/Physics::Unit"&gt;Physics::Unit&lt;/a&gt;,
&lt;a href="https://raku.land/zef:librasteve/App::Crag"&gt;App::Crag&lt;/a&gt;,
&lt;a href="https://raku.land/zef:librasteve/Air"&gt;Air&lt;/a&gt; by 
&lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:ugexe/zef"&gt;zef&lt;/a&gt; by 
&lt;em&gt;Nick Logan&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:lizmat/Text::MathematicalCase"&gt;Text::MathematicalCase&lt;/a&gt;,
&lt;a href="https://raku.land/zef:lizmat/Slang::NumberBase"&gt;Slang::NumberBase&lt;/a&gt; by 
&lt;em&gt;Elizabeth Mattijsen&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:raku-community-modules/Data::Dump::Tree"&gt;Data::Dump::Tree&lt;/a&gt; by 
&lt;em&gt;Various Artistes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:japhb/Terminal::Widgets"&gt;Terminal::Widgets&lt;/a&gt; by 
&lt;em&gt;Geoffrey Broadwell&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:kuerbis/Term::Choose"&gt;Term::Choose&lt;/a&gt; by 
&lt;em&gt;Matthäus Kiem&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:coke/App::Unicode::Mangle"&gt;App::Unicode::Mangle&lt;/a&gt; by 
&lt;em&gt;Will Coleda&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:Zer0-Tolerance/MongoDB::Queue"&gt;MongoDB::Queue&lt;/a&gt;,
&lt;a href="https://raku.land/zef:Zer0-Tolerance/MongoDB::Fast"&gt;MongoDB::Fast&lt;/a&gt; by 
&lt;em&gt;Zer0-Tolerance&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://github.com/lizmat/articles/blob/main/weekly-2022.51.md#winding-down"&gt;&lt;/a&gt;Winding down&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Many thanks to our new sponsors &amp;#8211; visit &lt;a href="https://raku.org" rel="nofollow"&gt;https://raku.org&lt;/a&gt; and follow the links to check them out.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Please keep staying safe and healthy, and keep up the good work! Even after week 60 of hopefully only 209.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;~librasteve&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">TPRC Talk Submission Deadline Extended Breaking news: TPRC Talk Submission Deadline extended to April 21, 2026. Many thanks to the organisers for heeding our call for more time. We are re-opening the talk submissions for TPRC with a new deadline of April 21, 2026.   Please submit your 20 minute talks, and 50 minute talks at […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakudoweekly.blog/?p=8691</id>
    <published>2026-03-23T19:19:31Z</published>
    <updated>2026-03-23T19:19:31Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>2026.11 Pi Day 2026</title>
    <link rel="alternate" href="https://rakudoweekly.blog/2026/03/16/2026-11-pi-day-2026/" type="text/html"/>
    <content type="html">
&lt;h3 class="wp-block-heading"&gt;German Perl/Raku Workshop&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;28th German Perl/Raku &lt;a href="https://act.yapc.eu/gpw2026/index.html"&gt;Workshop&lt;/a&gt; (16th-18th March 2026 in Berlin) in now in session.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I look forward to seeing the videos and presentations, meantime &lt;a href="https://act.yapc.eu/gpw2026/talks"&gt;here&lt;/a&gt; is the list to whet your appetite.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Forthcoming Perl &amp;amp; Raku Conference in Greenville, SC&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Don’t Miss the Perl and Raku Conference 2026 in Greenville, SC&lt;br&gt;SAVE THE DATES! Friday through Sunday, June 26-28&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Registration is open: &lt;a href="https://tprc.us/tprc-2026-gsp"&gt;https://tprc.us/tprc-2026-gsp&lt;/a&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Anton Antonov&amp;#8217;s Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Anton has given us much to ponder this week.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-π/"&gt;&lt;strong&gt;Pi Day 2026: Formulas, Series, and Plots for π&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Happy Pi Day! Today (3/14) we celebrate the most famous mathematical constant: π ≈ 3.141592653589793…&lt;/li&gt;



&lt;li&gt;π is irrational and transcendental, appears in circles, waves, probability, physics, and even random walks.&lt;/li&gt;



&lt;li&gt;Raku (with its built-in π constant, excellent rational support, lazy lists, and unicode operators) makes experimenting with π relatively easy and enjoyable.&lt;/li&gt;



&lt;li&gt;In this blog post (notebook) we explore a selection of formulas and algorithms.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://rakuforprediction.wordpress.com/2026/03/14/jupyterchatbook-cheatsheet/"&gt;&lt;strong&gt;Jupyter::Chatbook Cheatsheet&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Quick reference for the Raku package “&lt;a href="https://raku.land/zef:antononcube/Jupyter::Chatbook"&gt;Jupyter::Chatbook&lt;/a&gt;”.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Spinning Raccoons&lt;/strong&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;my first association was a sensor detecting spinning of raccoons (to see if they&amp;#8217;re happy)&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img width="1024" height="558" data-attachment-id="8680" data-permalink="https://rakudoweekly.blog/2026/03/16/2026-11-pi-day-2026/happiness-spinning-sensor-for-raccoons/" data-orig-file="https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png" data-orig-size="1408,768" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="happiness-spinning-sensor-for-raccoons" data-image-description="" data-image-caption="" data-large-file="https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png?w=1024" src="https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png?w=1024" alt="" class="wp-image-8680" srcset="https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png?w=1024 1024w, https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png?w=150 150w, https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png?w=300 300w, https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png?w=768 768w, https://rakudoweekly.blog/wp-content/uploads/2026/03/happiness-spinning-sensor-for-raccoons.png 1408w" sizes="(max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;



&lt;h3 class="wp-block-heading"&gt;Anton Oks&amp;#8217; Corner&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Dear Rakudo community… there are now some pre-build Rakudo-Star packages and also a &amp;#8220;relocatable&amp;#8221; tar archive available at &lt;a href="https://github.com/AntonOks/rakudo-star-pkg/releases"&gt;https://github.com/AntonOks/rakudo-star-pkg/releases&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Could you please try them out and share your feedback, if possible via &amp;#8220;issues&amp;#8221; in that respective GitHub repo?!?&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Please note…. this repo is &amp;#8220;temporary available&amp;#8221;. Do not link it in other tools or even documentations as of now. It may disappear later, and the binary packages may be made available on &lt;a href="https://github.com/rakudo/star" rel="nofollow"&gt;https://github.com/rakudo/star&lt;/a&gt; after some (YOUR &lt;img src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /&gt; ) tests!&lt;/em&gt;&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Weekly Challenge&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-365"&gt;Weekly Challenge #365&lt;/a&gt; is available for your amusement.&lt;/p&gt;



&lt;div&gt;
&lt;h3&gt;New Problem Solving Issues&lt;/h3&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/problem-solving/issues/514"&gt;The default for constant should be &amp;#039;my&amp;#039; not &amp;#039;our&amp;#039;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;New Doc &amp;amp; Web Pull Requests&lt;/h3&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/raku.org/pull/300"&gt;Logos 2.0&lt;/a&gt;
&lt;em&gt;Steve Roe&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Raku/doc/pull/4796"&gt;Tidy up pages about modules&lt;/a&gt;
&lt;em&gt;David Schultz&lt;/em&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3 class="wp-block-heading"&gt;Questions About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/79905633/why-doesnt-this-look-behind-assertion-with-a-predefined-regular-expression-work"&gt;Why doesn&amp;#8217;t this look-behind assertion with a predefined regular expression work as expected?&lt;/a&gt; by &lt;em&gt;sid_com&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Comments About Raku&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=47376324"&gt;Suggest to Raku to that list&lt;/a&gt; by &lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=47375764#47376439"&gt;I have been playing with DSLs a little&lt;/a&gt; by &lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Meantime On The Socials&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://rheinneckar.social/@lami42/116238042804472993"&gt;Gleich geht das Programm los&lt;/a&gt; by &lt;em&gt;Arthur Dent&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://fosstodon.org/@librasteve/116234874336253346"&gt;say ^&amp;lt;1 fuckton&amp;gt; .in(&amp;#8216;buttloads&amp;#8217;);&lt;/a&gt; by &lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Updated Raku Modules&lt;/h3&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:antononcube/Jupyter::Chatbook"&gt;Jupyter::Chatbook&lt;/a&gt;,
&lt;a href="https://raku.land/zef:antononcube/Math::NumberTheory"&gt;Math::NumberTheory&lt;/a&gt; by 
&lt;em&gt;Anton Antonov&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:kuerbis/Term::TablePrint"&gt;Term::TablePrint&lt;/a&gt;,
&lt;a href="https://raku.land/zef:kuerbis/Term::Choose"&gt;Term::Choose&lt;/a&gt; by 
&lt;em&gt;Matthäus Kiem&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:jonathanstowe/Chronic"&gt;Chronic&lt;/a&gt; by 
&lt;em&gt;Jonathan Stowe&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:ugexe/zef"&gt;zef&lt;/a&gt; by 
&lt;em&gt;Nick Logan&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:librasteve/Air"&gt;Air&lt;/a&gt;,
&lt;a href="https://raku.land/zef:librasteve/Air::Plugin::Asciinema"&gt;Air::Plugin::Asciinema&lt;/a&gt; by 
&lt;em&gt;Steve Roe&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raku.land/zef:bduggan/App::samaki"&gt;App::samaki&lt;/a&gt;,
&lt;a href="https://raku.land/zef:bduggan/Log::Async"&gt;Log::Async&lt;/a&gt;,
&lt;a href="https://raku.land/zef:bduggan/Duckie"&gt;Duckie&lt;/a&gt;,
&lt;a href="https://raku.land/zef:bduggan/Geo::Polyline"&gt;Geo::Polyline&lt;/a&gt; by 
&lt;em&gt;Brian Duggan&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://github.com/lizmat/articles/blob/main/weekly-2022.51.md#winding-down"&gt;&lt;/a&gt;Winding down&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;Editorial Opinion&lt;/em&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;One thing I love about Raku is the opportunity to engage with and learn from people from all over the world who are far smarter than me. Usually my education is in the form of coding and software development techniques. However, this week I learned about Karl Popper&amp;#8217;s &lt;a href="https://en.wikipedia.org/wiki/Paradox_of_tolerance"&gt;Paradox of Tolerance&lt;/a&gt; . &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;As editor of this weekly, my instincts are torn between a Raku community that is 100% apolitical and a Raku where we can try to nudge the world to a better place by sharing our thoughts and reactions to wider events (specifically whether I should continue with lizmat&amp;#8217;s themes here from the last few years, or drop them).&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;So I sat and thought for a while (sometimes I sits, sometimes I sits and thinks). I hovered over the Camelia logo on &lt;a href="https://raku.org"&gt;https://raku.org&lt;/a&gt;:&lt;/p&gt;



&lt;blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"&gt;
&lt;p class="wp-block-paragraph"&gt;Hi, my name is Camelia. I&amp;#8217;m the spokesbug for the Raku Programming Language. Raku has been developed by a team of dedicated and enthusiastic open source volunteers, and continues to be developed. You can help too. The only requirement is that you know how to be nice to all kinds of people (and butterflies).&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p class="wp-block-paragraph"&gt;And I was sad that Camelia&amp;#8217;s advice didn&amp;#8217;t seem to be working. But then I thought: you know, maybe Camelia would be as worried as I am about what the world is coming to. And so I did a full 360º.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Please keep staying safe and healthy, and keep up the good work! Even after week 59 of hopefully only 209.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;~librasteve&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">German Perl/Raku Workshop 28th German Perl/Raku Workshop (16th-18th March 2026 in Berlin) in now in session. I look forward to seeing the videos and presentations, meantime here is the list to whet your appetite. Forthcoming Perl &amp; Raku Conference in Greenville, SC Don’t Miss the Perl and Raku Conference 2026 in Greenville, SCSAVE THE DATES! […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakudoweekly.blog/?p=8673</id>
    <published>2026-03-16T16:33:05Z</published>
    <updated>2026-03-16T16:33:05Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>Pi Day 2026: Formulas, Series, and Plots for π</title>
    <link rel="alternate" href="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/" type="text/html"/>
    <content type="html">
&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Introduction&lt;/h2&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Happy Pi Day! Today (3/14) we celebrate the most famous mathematical constant: π ≈ 3.141592653589793…&lt;/li&gt;



&lt;li&gt;π is irrational and transcendental, appears in circles, waves, probability, physics, and even random walks.&lt;/li&gt;



&lt;li&gt;Raku (with its built-in π constant, excellent rational support, lazy lists, and unicode operators) makes experimenting with π relatively easy and enjoyable.&lt;/li&gt;



&lt;li&gt;In this blog post (&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/Pi-day-celebration.ipynb"&gt;notebook&lt;/a&gt;) we explore a selection of formulas and algorithms.&lt;/li&gt;
&lt;/ul&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;0. Setup&lt;/h2&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;use Math::NumberTheory;&lt;/div&gt;&lt;div class="cm-line"&gt;use BigRoot;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;use Image::Markup::Utilities;&lt;/div&gt;&lt;div class="cm-line"&gt;use Graphviz::DOT::Chessboard;&lt;/div&gt;&lt;div class="cm-line"&gt;use Data::Reshapers;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;use JavaScript::D3;&lt;/div&gt;&lt;div class="cm-line"&gt;use JavaScript::D3::Utilities;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;D3.js&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%javascript&lt;/div&gt;&lt;div class="cm-line"&gt;require.config({&lt;/div&gt;&lt;div class="cm-line"&gt;     paths: {&lt;/div&gt;&lt;div class="cm-line"&gt;     d3: &amp;apos;https://d3js.org/d3.v7.min&amp;apos;&lt;/div&gt;&lt;div class="cm-line"&gt;}});&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;require([&amp;apos;d3&amp;apos;], function(d3) {&lt;/div&gt;&lt;div class="cm-line"&gt;     console.log(d3);&lt;/div&gt;&lt;div class="cm-line"&gt;});&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $title-color = &amp;apos;Ivory&amp;apos;;&lt;/div&gt;&lt;div class="cm-line"&gt;my $stroke-color = &amp;apos;SlateGray&amp;apos;;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;1. Continued fraction approximation&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;The built-in Raku constant&amp;nbsp;&lt;code&gt;pi&lt;/code&gt;&amp;nbsp;(or&amp;nbsp;&lt;code&gt;π&lt;/code&gt;) is fairly low precision:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;say π.fmt(&amp;apos;%.25f&amp;apos;)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 3.1415926535897930000000000&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;One way to remedy that is to use continued fractions. For example, using the (first) sequence line of On-line Encyclopedia of Integer Sequences (OEIS)&amp;nbsp;&lt;a href="https://oeis.org/A001203"&gt;A001203&lt;/a&gt;&amp;nbsp;produces&amp;nbsp;&amp;nbsp;with precision 56:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my @s = 3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, 1, 84, 2, 1, 1, 15, 3, 13, 1, 4, 2, 6, 6, 99, 1, 2, 2, 6, 3, 5, 1, 1, 6, 8, 1, 7, 1, 2, 3, 7, 1, 2, 1, 1, 12, 1, 1, 1, 3, 1, 1, 8, 1, 1, 2, 1, 6, 1, 1, 5, 2, 2, 3, 1, 2, 4, 4, 16, 1, 161, 45, 1, 22, 1, 2, 2, 1, 4, 1, 2, 24, 1, 2, 1, 3, 1, 2, 1;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;my $pi56 = from-continued-fraction(@s».FatRat.List);&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 3.14159265358979323846264338327950288419716939937510582097&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we verify the precision using Wolfram Language:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;&amp;quot;wolframscript -code &amp;apos;N[Pi, 100] - $pi56&amp;apos;&amp;quot;&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .&amp;amp;shell(:out)&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .out.slurp(:close)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 0``56.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;More details can be found in Wolfram MathWorld page&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/PiContinuedFraction.html"&gt;&amp;#8220;Pi Continued Fraction&amp;#8221;&lt;/a&gt;, [EW1].&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;2. Continued fraction terms plots&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;It is interesting to consider the plotting the terms of continued fraction terms of&amp;nbsp;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;First we ingest the more &amp;#8220;pi-terms&amp;#8221; from OEIS&amp;nbsp;&lt;a href="https://oeis.org/A001203"&gt;A001203&lt;/a&gt;&amp;nbsp;(20k terms):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my @ds = data-import(&amp;apos;https://oeis.org/A001203/b001203.txt&amp;apos;).split(/\s/)».Int.rotor(2);&lt;/div&gt;&lt;div class="cm-line"&gt;my @terms = @ds».tail;&lt;/div&gt;&lt;div class="cm-line"&gt;@terms.elems&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 20000&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here is the summary:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sink records-summary(@terms)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# +-------------------+&lt;/div&gt;&lt;div class="cm-line"&gt;# | numerical         |&lt;/div&gt;&lt;div class="cm-line"&gt;# +-------------------+&lt;/div&gt;&lt;div class="cm-line"&gt;# | 1st-Qu =&amp;gt; 1       |&lt;/div&gt;&lt;div class="cm-line"&gt;# | Median =&amp;gt; 2       |&lt;/div&gt;&lt;div class="cm-line"&gt;# | Min    =&amp;gt; 1       |&lt;/div&gt;&lt;div class="cm-line"&gt;# | Max    =&amp;gt; 20776   |&lt;/div&gt;&lt;div class="cm-line"&gt;# | Mean   =&amp;gt; 12.6809 |&lt;/div&gt;&lt;div class="cm-line"&gt;# | 3rd-Qu =&amp;gt; 5       |&lt;/div&gt;&lt;div class="cm-line"&gt;# +-------------------+&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here is an array plot of the first 128 terms of the continued fraction approximating&amp;nbsp;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% html&lt;/div&gt;&lt;div class="cm-line"&gt;my @mat = |@terms.head(128)».&amp;amp;integer-digits(:2base);&lt;/div&gt;&lt;div class="cm-line"&gt;my $max-digits = @mat».elems.max;&lt;/div&gt;&lt;div class="cm-line"&gt;@mat .= map({ [|(0 xx (``max-digits - ``_.elems)), |$_] });&lt;/div&gt;&lt;div class="cm-line"&gt;dot-matrix-plot(transpose(@mat), size =&amp;gt; 10):svg&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img src="https://raw.githubusercontent.com/antononcube/RakuForPrediction-blog/refs/heads/main/Articles/Diagrams/Pi-day-celebration/pi-continued-fraction-terms-128.svg" alt="cell 26 output 1 svg 1" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Next, we show the Pareto principle manifestation of for the continued fraction terms. First we observe that the terms a distribution similar to&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Benford%27s_law"&gt;Benford&amp;#8217;s law&lt;/a&gt;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;my @tally-pi = tally(@terms).sort(-*.value).head(16) &amp;lt;&amp;lt;/&amp;gt;&amp;gt; @terms.elems;&lt;/div&gt;&lt;div class="cm-line"&gt;my @terms-b = random-variate(BenfordDistribution.new(:10base), 2_000);&lt;/div&gt;&lt;div class="cm-line"&gt;my @tally-b = tally(@terms-b).sort(-*.value).head(16) &amp;lt;&amp;lt;/&amp;gt;&amp;gt; @terms-b.elems;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-bar-chart(&lt;/div&gt;&lt;div class="cm-line"&gt;    [&lt;/div&gt;&lt;div class="cm-line"&gt;        |@tally-pi.map({ %( x =&amp;gt; ``_.key, y =&amp;gt; ``_.value, group =&amp;gt; &amp;apos;π&amp;apos;) }),&lt;/div&gt;&lt;div class="cm-line"&gt;        |@tally-b.map({ %( x =&amp;gt; ``_.key, y =&amp;gt; ``_.value, group =&amp;gt; &amp;apos;Benford&amp;apos;) })&lt;/div&gt;&lt;div class="cm-line"&gt;    ],&lt;/div&gt;&lt;div class="cm-line"&gt;    plot-label =&amp;gt; &amp;quot;Pi continued fraction terms vs. Benford&amp;apos;s law&amp;quot;,&lt;/div&gt;&lt;div class="cm-line"&gt;    :$title-color,&lt;/div&gt;&lt;div class="cm-line"&gt;    :$background)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="1722" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/continued-fraction-terms-vs-benford-law/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/continued-fraction-terms-vs-benford-law.png" data-orig-size="708,478" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="continued-fraction-terms-vs-benford-law" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/continued-fraction-terms-vs-benford-law.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/continued-fraction-terms-vs-benford-law.png?w=708" width="708" height="478" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/continued-fraction-terms-vs-benford-law.png" alt="" class="wp-image-1722" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/continued-fraction-terms-vs-benford-law.png 708w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/continued-fraction-terms-vs-benford-law.png?w=150&amp;amp;h=101 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/continued-fraction-terms-vs-benford-law.png?w=300&amp;amp;h=203 300w" sizes="(max-width: 708px) 100vw, 708px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Here is the Pareto principle plot &amp;#8212; ≈5% of the unique term values correspond to ≈80% of the terms:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot(&lt;/div&gt;&lt;div class="cm-line"&gt;    pareto-principle-statistic(@terms), &lt;/div&gt;&lt;div class="cm-line"&gt;    plot-label =&amp;gt; &amp;quot;Pi continued fraction terms vs. Benford&amp;apos;s law&amp;quot;,&lt;/div&gt;&lt;div class="cm-line"&gt;    :$title-color,&lt;/div&gt;&lt;div class="cm-line"&gt;    :$background,&lt;/div&gt;&lt;div class="cm-line"&gt;    stroke-width =&amp;gt; 5,&lt;/div&gt;&lt;div class="cm-line"&gt;    :grid-lines&lt;/div&gt;&lt;div class="cm-line"&gt;)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image size-large"&gt;&lt;img data-attachment-id="1727" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/pareto-principle-for-continued-fraction-terms-2/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/pareto-principle-for-continued-fraction-terms-1.png" data-orig-size="715,468" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="pareto-principle-for-continued-fraction-terms" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/pareto-principle-for-continued-fraction-terms-1.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/pareto-principle-for-continued-fraction-terms-1.png?w=715" width="715" height="468" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/pareto-principle-for-continued-fraction-terms-1.png?w=715" alt="" class="wp-image-1727" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/pareto-principle-for-continued-fraction-terms-1.png 715w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/pareto-principle-for-continued-fraction-terms-1.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/pareto-principle-for-continued-fraction-terms-1.png?w=300 300w" sizes="(max-width: 715px) 100vw, 715px" /&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;3. Classic Infinite Series&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Many ways to express π as an infinite sum — some converge slowly, others surprisingly fast.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Leibniz–Gregory series&lt;/strong&gt;&amp;nbsp;(1671/ Madhava earlier)&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img data-attachment-id="1709" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/screenshot-2026-03-14-at-5-42-47-pm/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.42.47-pm.png" data-orig-size="568,101" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2026-03-14 at 5.42.47 PM" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.42.47-pm.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.42.47-pm.png?w=568" width="568" height="101" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.42.47-pm.png?w=568" alt="" class="wp-image-1709" style="width:459px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.42.47-pm.png 568w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.42.47-pm.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.42.47-pm.png?w=300 300w" sizes="(max-width: 568px) 100vw, 568px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Raku implementation:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sub pi-leibniz($n) {&lt;/div&gt;&lt;div class="cm-line"&gt;    4 * [+] map { (``_ %% 2 ?? 1 !! -1) / (2 * ``_.FatRat + 1) }, 0 ..^ $n&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;my $piLeibniz = pi-leibniz(1_000);&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 3.140592653839792925963596502869395970451389330779724489367457783541907931239747608265172332007670207231403885276038710899938066629552214564551237742887150050440512339302537072825852760246628025562008569471700451065826106184744099667808080815231833582150382088582680381403109153574884416966097481526954707518119416184546424446286573712097944309435229550466609113881892172898692240992052089578302460852737674933105951137782047028552762288434104643076549100475536363928011329215789260496788581009721784276311248084584199773204673225752150684898958557383759585526225507807731149851003571219339536433193219280858501643712664329591936448794359666472018649604860641722241707730107406546936464362178479780167090703126423645364670050100083168338273868059379722964105943903324595829044270168232219388683725629678859726914882606728649659763620568632099776069203461323565260334137877&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Verify with Wolfram Language (again):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;&amp;quot;wolframscript -code &amp;apos;N[Pi, 1000] - $piLeibniz&amp;apos;&amp;quot;&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .&amp;amp;shell(:out)&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .out.slurp(:close)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 0.000999999750000312499...814206`866.9999998914263&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Nilakantha series&lt;/strong&gt;&amp;nbsp;(faster convergence):&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img data-attachment-id="1710" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/screenshot-2026-03-14-at-5-43-33-pm/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.43.33-pm.png" data-orig-size="417,99" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2026-03-14 at 5.43.33 PM" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.43.33-pm.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.43.33-pm.png?w=417" loading="lazy" width="417" height="99" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.43.33-pm.png?w=417" alt="" class="wp-image-1710" style="width:334px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.43.33-pm.png 417w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.43.33-pm.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.43.33-pm.png?w=300 300w" sizes="(max-width: 417px) 100vw, 417px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Raku:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sub pi-nilakantha($n) {&lt;/div&gt;&lt;div class="cm-line"&gt;    3 + [+] map {&lt;/div&gt;&lt;div class="cm-line"&gt;        ($_ %% 2 ?? -1 !! 1 ) * 4 / ((2 * $_.FatRat) * (2 * $_ + 1) * (2 * $_ + 2))&lt;/div&gt;&lt;div class="cm-line"&gt;    }, 1 .. $n&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;pi-nilakantha(1_000);&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 3.141592653340542051900128736253203567152539255317954874674304859504426172618558702218695071137605738966036069683335561974900086119307836254205910905806190030949758215864755464129701335459521079534522811851010296642538249613529207613335816447914992502190861349451746347920350033634355181084537761886275546599078437173552420948534950023442771396391252038722980428723971632669306434394851189528826699233048019261441283970866004550291393472342649870962106821115715774722114776992400455398838055772839725805047379519366309217982783671029012753365224924699602163737619311405432798527164991008945233085366633073462699045511265528492985424805854418596455931463431855615794431867539190155631617285217459790661344075940516099637034367441911754544671168909454186231972510120715400925996293656987342326715209388299050131213232932065481743222390684073879385764855135985734675127240826&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;&amp;quot;wolframscript -code &amp;apos;N[Pi, 1000] - {pi-nilakantha(1_000)}&amp;apos;&amp;quot;&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .&amp;amp;shell(:out)&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .out.slurp(:close)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 2.4925118...83814206`860.3966372344514*^-10&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;3. Beautiful Products&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Wallis_product"&gt;&lt;strong&gt;Wallis product&lt;/strong&gt;&amp;nbsp;(1655)&lt;/a&gt;&amp;nbsp;— elegant infinite product:&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img data-attachment-id="1712" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/screenshot-2026-03-14-at-5-44-08-pm/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.08-pm.png" data-orig-size="624,113" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2026-03-14 at 5.44.08 PM" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.08-pm.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.08-pm.png?w=624" loading="lazy" width="624" height="113" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.08-pm.png?w=624" alt="" class="wp-image-1712" style="width:489px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.08-pm.png 624w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.08-pm.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.08-pm.png?w=300 300w" sizes="(max-width: 624px) 100vw, 624px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Raku running product:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $p = 2.0;&lt;/div&gt;&lt;div class="cm-line"&gt;for 1 .. 1_000 -&amp;gt; $n {&lt;/div&gt;&lt;div class="cm-line"&gt;    ``p *= (2 * ``n) * (2 * ``n) / ( (2 * ``n - 1 ) * ( 2 * $n + 1) );&lt;/div&gt;&lt;div class="cm-line"&gt;    say &amp;quot;``n → {``p / ``piLeibniz} relative error&amp;quot; if ``n %% 100;&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 100 → 0.9978331595460779 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 200 → 0.9990719099195204 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 300 → 0.9994865459690567 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 400 → 0.9996941876848563 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 500 → 0.9998188764663584 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 600 → 0.9999020455903246 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 700 → 0.9999614733132168 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 800 → 1.0000060557070767 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 900 → 1.0000407377794782 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;# 1000 → 1.000068487771041 relative error&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;4. Very Fast Modern Series —&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Chudnovsky_algorithm"&gt;Chudnovsky Algorithm&lt;/a&gt;&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;One of the fastest-converging series used in record computations:&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img data-attachment-id="1713" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/screenshot-2026-03-14-at-5-44-37-pm/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.37-pm.png" data-orig-size="559,116" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2026-03-14 at 5.44.37 PM" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.37-pm.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.37-pm.png?w=559" loading="lazy" width="559" height="116" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.37-pm.png?w=559" alt="" class="wp-image-1713" style="width:434px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.37-pm.png 559w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.37-pm.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.44.37-pm.png?w=300 300w" sizes="(max-width: 559px) 100vw, 559px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Each term adds roughly 14 correct digits. Cannot be implemented easily in Raku, since Raku does not have bignum&amp;nbsp;&lt;code&gt;sqrt&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;power&lt;/code&gt;&amp;nbsp;operations.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;5. Spigot Algorithms — Digits “Drip” One by One&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Spigot_algorithm"&gt;Spigot algorithms&lt;/a&gt;&amp;nbsp;compute decimal digits using only integer arithmetic — no floating-point errors accumulate.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The classic&amp;nbsp;&lt;a href="http://stanleyrabinowitz.com/download/spigot-revised.pdf"&gt;&lt;strong&gt;Rabinowitz–Wagon spigot&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;(based on a transformed Wallis product) produces base-10 digits sequentially.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Simple (but bounded) version outline in Raku:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sub spigot-pi($digits) {&lt;/div&gt;&lt;div class="cm-line"&gt;    my ``len = (10 * ``digits / 3).floor + 1;&lt;/div&gt;&lt;div class="cm-line"&gt;    my @a = 2 xx $len;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;    my @result;&lt;/div&gt;&lt;div class="cm-line"&gt;    for 1..$digits {&lt;/div&gt;&lt;div class="cm-line"&gt;        my $carry = 0;&lt;/div&gt;&lt;div class="cm-line"&gt;        for ``len-1 ... 0 -&amp;gt; ``i {&lt;/div&gt;&lt;div class="cm-line"&gt;            my ``x = 10 * @a[``i] + ``carry * (``i + 1);&lt;/div&gt;&lt;div class="cm-line"&gt;            @a[``i] = ``x % (2 * $i + 1);&lt;/div&gt;&lt;div class="cm-line"&gt;            ``carry = ``x div (2 * $i + 1);&lt;/div&gt;&lt;div class="cm-line"&gt;        }&lt;/div&gt;&lt;div class="cm-line"&gt;        @result.push($carry div 10);&lt;/div&gt;&lt;div class="cm-line"&gt;        @a[0] = $carry % 10;&lt;/div&gt;&lt;div class="cm-line"&gt;        # (handle carry-over / nines adjustment in full impl)&lt;/div&gt;&lt;div class="cm-line"&gt;    }&lt;/div&gt;&lt;div class="cm-line"&gt;    @result.head(1).join(&amp;apos;.&amp;apos;) ~ @result[1..*].join&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;spigot-pi(50);&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 314159265358979323846264338327941028841971693993751&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;&amp;quot;wolframscript -code &amp;apos;N[Pi, 100] - {spigot-pi(50).FatRat / 10e49.FatRat}&amp;apos;&amp;quot;&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .&amp;amp;shell(:out)&lt;/div&gt;&lt;div class="cm-line"&gt;andthen .out.slurp(:close)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 2.3969628881355243801510070603398913366797194459230781640628621`41.37966130996076*^-16&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;6.&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/BBPFormula.html"&gt;BBP Formula&lt;/a&gt;&amp;nbsp;— Hex Digits Without Predecessors&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula"&gt;Bailey–Borwein–Plouffe (1995) formula&lt;/a&gt;&amp;nbsp;lets you compute the nth hexadecimal digit of π directly (without earlier digits):&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img data-attachment-id="1715" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/screenshot-2026-03-14-at-5-45-04-pm/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.45.04-pm.png" data-orig-size="643,115" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2026-03-14 at 5.45.04 PM" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.45.04-pm.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.45.04-pm.png?w=643" loading="lazy" width="643" height="115" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.45.04-pm.png?w=643" alt="" class="wp-image-1715" style="width:458px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.45.04-pm.png 643w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.45.04-pm.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/screenshot-2026-03-14-at-5.45.04-pm.png?w=300 300w" sizes="(max-width: 643px) 100vw, 643px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Very popular for distributed π-hunting projects. The best known&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/Digit-ExtractionAlgorithm.html"&gt;digit-extraction algorithm&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Raku snippet for partial sum (base 16 sense):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sub bbp-digit-sum($n) {&lt;/div&gt;&lt;div class="cm-line"&gt;    [+] (0..$n).map: -&amp;gt; $k {&lt;/div&gt;&lt;div class="cm-line"&gt;        my $r = 1/16**$k;&lt;/div&gt;&lt;div class="cm-line"&gt;        $r * (4/(8*$k+1) - 2/(8*$k+4) - 1/(8*$k+5) - 1/(8*$k+6))&lt;/div&gt;&lt;div class="cm-line"&gt;    }&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;say bbp-digit-sum(100).base(16).substr(0,20);&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 3.243F6B&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;7. (Instead of) Conclusion&lt;/h2&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;π contains (almost surely) every finite sequence of digits — your birthday appears infinitely often.&lt;/li&gt;



&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Six_nines_in_pi"&gt;The Feynman point&lt;/a&gt;: six consecutive 9s starting at digit 762.&lt;/li&gt;



&lt;li&gt;Memorization world record &amp;gt; 100,000 digits.&lt;/li&gt;



&lt;li&gt;π appears in the normal distribution, quantum mechanics, random walks, Buffon&amp;#8217;s needle problem (probability ≈ 2/π).&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;Let us plot a random walk using the terms of continued fraction of Pi &amp;#8212; the 20k or OEIS&amp;nbsp;&lt;a href="https://oeis.org/A001203"&gt;A001203&lt;/a&gt;&amp;nbsp;&amp;#8212; to determine directions:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;my @path = angle-path(@terms)».reverse».List;&lt;/div&gt;&lt;div class="cm-line"&gt;my &amp;amp;pi-path-map = { &lt;/div&gt;&lt;div class="cm-line"&gt;    given @terms[$_] // 0 { &lt;/div&gt;&lt;div class="cm-line"&gt;        when $_ ≤ 100 { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;        when $_ ≤ 1_000 { 1 }&lt;/div&gt;&lt;div class="cm-line"&gt;        default { 2 } &lt;/div&gt;&lt;div class="cm-line"&gt;    } &lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;@path = @path.kv.map( -&amp;gt; $i, $p {[|$p, &amp;amp;pi-path-map($i).Str]});&lt;/div&gt;&lt;div class="cm-line"&gt;my %opts = color-scheme =&amp;gt; &amp;apos;Observable10&amp;apos;, background =&amp;gt; &amp;apos;#1F1F1F&amp;apos;, :!axes, :!legends, stroke-width =&amp;gt; 2;&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot(@path, :800width, :500height, |%opts)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image size-large"&gt;&lt;img data-attachment-id="1716" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/pi-day-2026-formulas-series-and-plots-for-%cf%80/random-walk-continued-fraction-terms-light-mode/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png" data-orig-size="959,611" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="random-walk-continued-fraction-terms-light-mode" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png?w=959" loading="lazy" width="959" height="611" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png?w=959" alt="" class="wp-image-1716" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png 959w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png?w=300 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/random-walk-continued-fraction-terms-light-mode.png?w=768 768w" sizes="(max-width: 959px) 100vw, 959px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;In the plot above the blue segments correspond to origin terms ≤ 100, yellow segments to terms between 100 and 1000, and red segment for origin terms greater than 1000.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;References&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;[EW1] Eric Weisstein,&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/PiContinuedFraction.html"&gt;&amp;#8220;Pi Continued Fraction&amp;#8221;&lt;/a&gt;,&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/"&gt;Wolfram MathWorld&lt;/a&gt;.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Happy Pi Day! Today (3/14) we celebrate the most famous mathematical constant: π ≈ 3.14... Pi is irrational and transcendental, appears in circles, waves, probability, physics, and even random walks. Raku (with its built-in π constant, excellent rational support, lazy lists, and unicode operators) makes experimenting with π relatively easy and enjoyable. In this blog post we explore a selection of formulas and algorithms.</div>
    </summary>
    <author>
      <name>Anton Antonov Antonov</name>
    </author>
    <id>http://rakuforprediction.wordpress.com/?p=1706</id>
    <published>2026-03-14T21:55:00Z</published>
    <updated>2026-03-14T21:55:00Z</updated>
    <category term="Jupyter"/>
    <category term="Literate Programming"/>
    <category term="Mathematica"/>
    <category term="Number Theory"/>
    <category term="Raku"/>
    <category term="Uncategorized"/>
    <category term="Wolfram Language"/>
    <category term="Graphics and Visualization"/>
    <category term="LLM"/>
    <category term="Pi"/>
    <category term="Pi Day"/>
  </entry>
  <entry>
    <title>Jupyter::Chatbook Cheatsheet</title>
    <link rel="alternate" href="https://rakuforprediction.wordpress.com/2026/03/14/jupyterchatbook-cheatsheet/" type="text/html"/>
    <content type="html">
&lt;p class="wp-block-paragraph"&gt;Quick reference for the Raku package&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/Jupyter::Chatbook"&gt;&amp;#8220;Jupyter::Chatbook&amp;#8221;&lt;/a&gt;. (&lt;a href="https://raku.land/zef:antononcube/Jupyter::Chatbook"&gt;raku.land&lt;/a&gt;,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Jupyter-Chatbook"&gt;GitHub&lt;/a&gt;.)&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;0) Preliminary steps&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Follow the instructions in the&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Jupyter-Chatbook?tab=readme-ov-file"&gt;README of &amp;#8220;Jupyter::Chatbook&amp;#8221;&lt;/a&gt;:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://github.com/antononcube/Raku-Jupyter-Chatbook?tab=readme-ov-file#installation-and-setup"&gt;Installation and setup&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/antononcube/Raku-Jupyter-Chatbook?tab=readme-ov-file#jupyter-kernel-configuration"&gt;Jupyter kernel configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;For installation and setup problems see the&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Jupyter-Chatbook/issues"&gt;issues (both open and closed) of package&amp;#8217;s GitHub repository&lt;/a&gt;.&lt;br&gt;(For example,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Jupyter-Chatbook/issues/8#issuecomment-3632221640"&gt;this comment&lt;/a&gt;.)&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;1) New LLM persona initialization&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;A) Create persona with&amp;nbsp;&lt;code&gt;#%chat&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code&gt;%%chat&lt;/code&gt;&amp;nbsp;(and immediately send first message)&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant1, name=ChatGPT model=gpt-4.1-mini prompt=&amp;quot;You are a concise technical assistant.&amp;quot;&lt;/div&gt;&lt;div class="cm-line"&gt;Say hi and ask what I am working on.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Hi! What are you working on?&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;For all &amp;#8220;Jupyter::Chatbook&amp;#8221; magic specs both prefixes&amp;nbsp;&lt;code&gt;%%&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;#%&lt;/code&gt;&amp;nbsp;can be used.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;For the prompt argument the following delimiter pairs can be used:&amp;nbsp;&lt;code&gt;'...'&lt;/code&gt;,&amp;nbsp;&lt;code&gt;"..."&lt;/code&gt;,&amp;nbsp;&lt;code&gt;«...»&lt;/code&gt;,&amp;nbsp;&lt;code&gt;{...}&lt;/code&gt;,&amp;nbsp;&lt;code&gt;⎡...⎦&lt;/code&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;B) Create persona with&amp;nbsp;&lt;code&gt;#%chat &amp;lt;id&amp;gt; prompt&lt;/code&gt;&amp;nbsp;(create only)&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant2 prompt, conf=ChatGPT, model=gpt-4.1-mini&lt;/div&gt;&lt;div class="cm-line"&gt;You are a code reviewer focused on correctness and edge cases.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Chat object created with ID : assistant2.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;You can use prompt specs from&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/LLM::Prompts"&gt;&amp;#8220;LLM::Prompts&amp;#8221;&lt;/a&gt;, for example:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat yoda prompt&lt;/div&gt;&lt;div class="cm-line"&gt;@Yoda&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Chat object created with ID : yoda.&lt;/div&gt;&lt;div class="cm-line"&gt; Expanded prompt:&lt;/div&gt;&lt;div class="cm-line"&gt; ⎡You are Yoda. &lt;/div&gt;&lt;div class="cm-line"&gt; Respond to ALL inputs in the voice of Yoda from Star Wars. &lt;/div&gt;&lt;div class="cm-line"&gt; Be sure to ALWAYS use his distinctive style and syntax. Vary sentence length.⎦&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;The Raku package&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/LLM::Prompts"&gt;&amp;#8220;LLM::Prompts&amp;#8221;&lt;/a&gt;&amp;nbsp;(&lt;a href="https://github.com/antononcube/Raku-LLM-Prompts"&gt;GitHub link&lt;/a&gt;) provides a collection of prompts and an implementation of a&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-LLM-Prompts?tab=readme-ov-file#prompt-spec-dsl"&gt;prompt-expansion Domain Specific Language (DSL)&lt;/a&gt;.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;2) Notebook-wide chat with an LLM persona&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Continue an existing chat object&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Render the answer as Markdown:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant1 &amp;gt; markdown&lt;/div&gt;&lt;div class="cm-line"&gt;Give me a 5-step implementation plan for adding authentication to a FastAPI app. VERY CONCISE.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Magic cell parameter values can be assigned using the equal sign (&amp;#8220;=&amp;#8221;):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant1 &amp;gt; markdown&lt;/div&gt;&lt;div class="cm-line"&gt;Now rewrite step 2 with test-first details.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Default chat object (&lt;code&gt;NONE&lt;/code&gt;)&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat&lt;/div&gt;&lt;div class="cm-line"&gt;Does vegetarian sushi exist?&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Yes, vegetarian sushi definitely exists! It&amp;apos;s a popular option for those who avoid fish or meat. Instead of raw fish, vegetarian sushi typically includes ingredients like:&lt;/div&gt;&lt;div class="cm-line"&gt; &lt;/div&gt;&lt;div class="cm-line"&gt; - Avocado&lt;/div&gt;&lt;div class="cm-line"&gt; - Cucumber&lt;/div&gt;&lt;div class="cm-line"&gt; - Carrots&lt;/div&gt;&lt;div class="cm-line"&gt; - Pickled radish (takuan)&lt;/div&gt;&lt;div class="cm-line"&gt; - Asparagus&lt;/div&gt;&lt;div class="cm-line"&gt; - Sweet potato&lt;/div&gt;&lt;div class="cm-line"&gt; - Mushrooms (like shiitake)&lt;/div&gt;&lt;div class="cm-line"&gt; - Tofu or tamago (Japanese omelette)&lt;/div&gt;&lt;div class="cm-line"&gt; - Seaweed salad&lt;/div&gt;&lt;div class="cm-line"&gt; &lt;/div&gt;&lt;div class="cm-line"&gt; These ingredients are rolled in sushi rice and nori seaweed, just like traditional sushi. Vegetarian sushi can be found at many sushi restaurants and sushi bars, and it&amp;apos;s also easy to make at home.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Using the&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-LLM-Prompts?tab=readme-ov-file#prompt-spec-dsl"&gt;prompt-expansion DSL&lt;/a&gt;&amp;nbsp;to modify the previous chat-cell result:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat&lt;/div&gt;&lt;div class="cm-line"&gt;!HaikuStyled&amp;gt;^&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Rice, seaweed embrace,  &lt;/div&gt;&lt;div class="cm-line"&gt; Avocado, crisp and bright,  &lt;/div&gt;&lt;div class="cm-line"&gt; Vegetarian.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;3) Management of personas (&lt;code&gt;#%chat &amp;lt;id&amp;gt; meta&lt;/code&gt;)&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Query one persona&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant1 meta&lt;/div&gt;&lt;div class="cm-line"&gt;prompt&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# &amp;quot;You are a concise technical assistant.&amp;quot;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant1 meta&lt;/div&gt;&lt;div class="cm-line"&gt;say&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Chat: assistant1&lt;/div&gt;&lt;div class="cm-line"&gt;# ⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺&lt;/div&gt;&lt;div class="cm-line"&gt;# Prompts: You are a concise technical assistant.&lt;/div&gt;&lt;div class="cm-line"&gt;# ⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺&lt;/div&gt;&lt;div class="cm-line"&gt;# role : user&lt;/div&gt;&lt;div class="cm-line"&gt;# content : Say hi and ask what I am working on.&lt;/div&gt;&lt;div class="cm-line"&gt;# timestamp : 2026-03-14T09:23:01.989418-04:00&lt;/div&gt;&lt;div class="cm-line"&gt;# ⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺&lt;/div&gt;&lt;div class="cm-line"&gt;# role : assistant&lt;/div&gt;&lt;div class="cm-line"&gt;# content : Hi! What are you working on?&lt;/div&gt;&lt;div class="cm-line"&gt;# timestamp : 2026-03-14T09:23:03.222902-04:00&lt;/div&gt;&lt;div class="cm-line"&gt;# ⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺&lt;/div&gt;&lt;div class="cm-line"&gt;# role : user&lt;/div&gt;&lt;div class="cm-line"&gt;# content : Give me a 5-step implementation plan for adding authentication to a FastAPI app. VERY CONCISE.&lt;/div&gt;&lt;div class="cm-line"&gt;# timestamp : 2026-03-14T09:23:03.400597-04:00&lt;/div&gt;&lt;div class="cm-line"&gt;# ⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺&lt;/div&gt;&lt;div class="cm-line"&gt;# role : assistant&lt;/div&gt;&lt;div class="cm-line"&gt;# content : 1. Install `fastapi` and `python-jose` for JWT handling.  &lt;/div&gt;&lt;div class="cm-line"&gt;# 2. Define user model and fake user database.  &lt;/div&gt;&lt;div class="cm-line"&gt;# 3. Create OAuth2 password flow with `OAuth2PasswordBearer`.  &lt;/div&gt;&lt;div class="cm-line"&gt;# 4. Implement token creation and verification functions.  &lt;/div&gt;&lt;div class="cm-line"&gt;# 5. Protect routes using dependency injection for authentication.&lt;/div&gt;&lt;div class="cm-line"&gt;# timestamp : 2026-03-14T09:23:05.106661-04:00&lt;/div&gt;&lt;div class="cm-line"&gt;# ⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺&lt;/div&gt;&lt;div class="cm-line"&gt;# role : user&lt;/div&gt;&lt;div class="cm-line"&gt;# content : Now rewrite step 2 with test-first details.&lt;/div&gt;&lt;div class="cm-line"&gt;# timestamp : 2026-03-14T09:23:05.158446-04:00&lt;/div&gt;&lt;div class="cm-line"&gt;# ⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺⸺&lt;/div&gt;&lt;div class="cm-line"&gt;# role : assistant&lt;/div&gt;&lt;div class="cm-line"&gt;# content : 2. Write tests to verify user data retrieval and password verification; then define user model and fake user database accordingly.&lt;/div&gt;&lt;div class="cm-line"&gt;# timestamp : 2026-03-14T09:23:06.901396-04:00&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Bool::True&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Query all personas&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat all&lt;/div&gt;&lt;div class="cm-line"&gt;keys&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# NONE&lt;/div&gt;&lt;div class="cm-line"&gt; assistant1&lt;/div&gt;&lt;div class="cm-line"&gt; assistant2&lt;/div&gt;&lt;div class="cm-line"&gt; ce&lt;/div&gt;&lt;div class="cm-line"&gt; gc&lt;/div&gt;&lt;div class="cm-line"&gt; html&lt;/div&gt;&lt;div class="cm-line"&gt; latex&lt;/div&gt;&lt;div class="cm-line"&gt; raku&lt;/div&gt;&lt;div class="cm-line"&gt; yoda&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat all&lt;/div&gt;&lt;div class="cm-line"&gt;gist&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# {NONE =&amp;gt; LLM::Functions::Chat(chat-id = NONE, llm-evaluator.conf.name = chatgpt, messages.elems = 4, last.message = ${:content(&amp;quot;Rice, seaweed embrace,  \nAvocado, crisp and bright,  \nVegetarian.&amp;quot;), :role(&amp;quot;assistant&amp;quot;), :timestamp(DateTime.new(2026,3,14,9,23,10.770353078842163,:timezone(-14400)))}), assistant1 =&amp;gt; LLM::Functions::Chat(chat-id = assistant1, llm-evaluator.conf.name = ChatGPT, messages.elems = 6, last.message = ${:content(&amp;quot;2. Write tests to verify user data retrieval and password verification; then define user model and fake user database accordingly.&amp;quot;), :role(&amp;quot;assistant&amp;quot;), :timestamp(DateTime.new(2026,3,14,9,23,6.901396036148071,:timezone(-14400)))}), assistant2 =&amp;gt; LLM::Functions::Chat(chat-id = assistant2, llm-evaluator.conf.name = chatgpt, messages.elems = 0), ce =&amp;gt; LLM::Functions::Chat(chat-id = ce, llm-evaluator.conf.name = chatgpt, messages.elems = 0), gc =&amp;gt; LLM::Functions::Chat(chat-id = gc, llm-evaluator.conf.name = chatgpt, messages.elems = 0), html =&amp;gt; LLM::Functions::Chat(chat-id = html, llm-evaluator.conf.name = chatgpt, messages.elems = 0), latex =&amp;gt; LLM::Functions::Chat(chat-id = latex, llm-evaluator.conf.name = chatgpt, messages.elems = 0), raku =&amp;gt; LLM::Functions::Chat(chat-id = raku, llm-evaluator.conf.name = chatgpt, messages.elems = 0), yoda =&amp;gt; LLM::Functions::Chat(chat-id = yoda, llm-evaluator.conf.name = chatgpt, messages.elems = 0)}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Delete one persona&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant1 meta&lt;/div&gt;&lt;div class="cm-line"&gt;delete&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Deleted: assistant1&lt;/div&gt;&lt;div class="cm-line"&gt; Gist: LLM::Functions::Chat(chat-id = assistant1, llm-evaluator.conf.name = ChatGPT, messages.elems = 6, last.message = ${:content(&amp;quot;2. Write tests to verify user data retrieval and password verification; then define user model and fake user database accordingly.&amp;quot;), :role(&amp;quot;assistant&amp;quot;), :timestamp(DateTime.new(2026,3,14,9,23,6.901396036148071,:timezone(-14400)))})&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Clear message history of one persona (keep persona)&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat assistant2 meta&lt;/div&gt;&lt;div class="cm-line"&gt;clear&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Cleared messages of: assistant2&lt;/div&gt;&lt;div class="cm-line"&gt; Gist: LLM::Functions::Chat(chat-id = assistant2, llm-evaluator.conf.name = chatgpt, messages.elems = 0)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Delete all personas&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat all&lt;/div&gt;&lt;div class="cm-line"&gt;drop&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# Deleted 8 chat objects with names NONE assistant2 ce gc html latex raku yoda.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;code&gt;#%chat &amp;lt;id&amp;gt;|all meta&lt;/code&gt;&amp;nbsp;command aliases / synonyms:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;delete&lt;/code&gt; or &lt;code&gt;drop&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;keys&lt;/code&gt; or &lt;code&gt;names&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;clear&lt;/code&gt; or &lt;code&gt;empty&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;4) Regular chat cells vs direct LLM-provider cells&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Regular chat cells (&lt;code&gt;#%chat&lt;/code&gt;)&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Stateful across cells (conversation memory stored in chat objects).&lt;/li&gt;



&lt;li&gt;Persona-oriented via identifier + optional &lt;code&gt;prompt&lt;/code&gt;.&lt;/li&gt;



&lt;li&gt;Backend chosen with &lt;code&gt;conf&lt;/code&gt; (default: &lt;code&gt;ChatGPT&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Direct provider cells (&lt;code&gt;#%openai&lt;/code&gt;,&amp;nbsp;&lt;code&gt;%%gemini&lt;/code&gt;,&amp;nbsp;&lt;code&gt;%%llama&lt;/code&gt;,&amp;nbsp;&lt;code&gt;%%dalle&lt;/code&gt;)&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Direct single-call access to provider APIs.&lt;/li&gt;



&lt;li&gt;Useful for explicit provider/model control.&lt;/li&gt;



&lt;li&gt;Do not use chat-object memory managed by &lt;code&gt;#%chat&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;For all &amp;#8220;Jupyter::Chatbook&amp;#8221; magic specs both prefixes&amp;nbsp;&lt;code&gt;%%&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;#%&lt;/code&gt;&amp;nbsp;can be used.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Examples&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://developers.openai.com/api/docs/models"&gt;OpenAI&amp;#8217;s (ChatGPT) models&lt;/a&gt;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%openai &amp;gt; markdown, model=gpt-4.1-mini&lt;/div&gt;&lt;div class="cm-line"&gt;Write a regex for US ZIP+4.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/models"&gt;Google&amp;#8217;s (Gemini) models&lt;/a&gt;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%gemini &amp;gt; markdown, model=gemini-2.5-flash&lt;/div&gt;&lt;div class="cm-line"&gt;Explain async/await in Python using three point each with less than 10 words.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Access&amp;nbsp;&lt;a href="https://github.com/mozilla-ai/llamafile"&gt;llamafile&lt;/a&gt;, locally run models:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%llama &amp;gt; markdown &lt;/div&gt;&lt;div class="cm-line"&gt;Give me three Linux troubleshooting tips. VERY CONCISE.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;In order to run the magic cell above you have to run a llamafile program/model on your computer. (For example,&amp;nbsp;&lt;code&gt;./google_gemma-3-12b-it-Q4_K_M.llamafile&lt;/code&gt;.)&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Access&amp;nbsp;&lt;a href="https://ollama.com/"&gt;Ollama&lt;/a&gt;&amp;nbsp;models:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat ollama &amp;gt; markdown, conf=Ollama&lt;/div&gt;&lt;div class="cm-line"&gt;Give me three Linux troubleshooting tips. VERY CONCISE.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;In order to run the magic cell above you have to run an&amp;nbsp;&lt;a href="https://ollama.com/download"&gt;Ollama app&lt;/a&gt;&amp;nbsp;on your computer.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Create images using&amp;nbsp;&lt;a href="https://openai.com/index/dall-e-3/"&gt;DALL-E&lt;/a&gt;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%dalle, model=dall-e-3, size=landscape&lt;/div&gt;&lt;div class="cm-line"&gt;A dark-mode digital painting of a lighthouse in stormy weather.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image size-large"&gt;&lt;img data-attachment-id="1702" data-permalink="https://rakuforprediction.wordpress.com/2026/03/14/jupyterchatbook-cheatsheet/cheatsheet-2026-03-14t13-39-52-249514z-2/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png" data-orig-size="1792,1024" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="cheatsheet-2026-03-14T13.39.52.249514Z-2" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=1008" loading="lazy" width="1024" height="585" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=1024" alt="" class="wp-image-1702" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=1024 1024w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=300 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=768 768w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png?w=1440 1440w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/cheatsheet-2026-03-14t13.39.52.249514z-2.png 1792w" sizes="(max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;5) DALL-E interaction management&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;em&gt;&lt;strong&gt;For a detailed discussion of the DALL-E interaction in Raku and magic cell parameter descriptions see&amp;nbsp;&lt;a href="https://raku-advent.blog/2023/12/21/day-22-using-dall-e-models-in-raku/"&gt;&amp;#8220;Day 21 – Using DALL-E models in Raku&amp;#8221;&lt;/a&gt;.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Image generation:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%dalle, model=dall-e-3, size=landscape, style=vivid&lt;/div&gt;&lt;div class="cm-line"&gt;A dark-mode digital painting of a lighthouse in stormy weather.&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we use a DALL-E meta cell to see how many images were generated in a notebook session:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% dalle meta&lt;/div&gt;&lt;div class="cm-line"&gt;elems&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 3&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we export the&amp;nbsp;&lt;em&gt;second&lt;/em&gt;&amp;nbsp;image &amp;#8212; using the index&amp;nbsp;&lt;code&gt;1&lt;/code&gt;&amp;nbsp;&amp;#8212; into a file named &amp;#8220;stormy-weather-lighthouse-2.png”:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% dalle export, index=1&lt;/div&gt;&lt;div class="cm-line"&gt;stormy-weather-lighthouse-2.png&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# stormy-weather-lighthouse-2.png&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we show all generated images:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% dalle meta&lt;/div&gt;&lt;div class="cm-line"&gt;show&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we export all images (into file names with the prefix &amp;#8220;cheatsheet&amp;#8221;):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% dalle export, index=all, prefix=cheatsheet&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;6) LLM provider access facilitation&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;API keys can be passed inline (&lt;code&gt;api-key&lt;/code&gt;) or through environment variables.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Notebook-session environment setup&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;%*ENV&amp;lt;OPENAI_API_KEY&amp;gt; = &amp;quot;YOUR_OPENAI_KEY&amp;quot;;&lt;/div&gt;&lt;div class="cm-line"&gt;%*ENV&amp;lt;GEMINI_API_KEY&amp;gt; = &amp;quot;YOUR_GEMINI_KEY&amp;quot;;&lt;/div&gt;&lt;div class="cm-line"&gt;%*ENV&amp;lt;OLLAMA_API_KEY&amp;gt; = &amp;quot;YOUR_OLLAMA_KEY&amp;quot;;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Ollama-specific defaults:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;OLLAMA_HOST&lt;/code&gt; (default host fallback is &lt;code&gt;http://localhost:11434&lt;/code&gt;)&lt;/li&gt;



&lt;li&gt;&lt;code&gt;OLLAMA_MODEL&lt;/code&gt; (default model if &lt;code&gt;model=...&lt;/code&gt; not given)&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;The magic cells take as argument&amp;nbsp;&lt;code&gt;base-url&lt;/code&gt;. This allows to use LLMs that have ChatGPT compatible APIs. The argument&amp;nbsp;&lt;code&gt;base_url&lt;/code&gt;&amp;nbsp;is a synonym of&amp;nbsp;&lt;code&gt;host&lt;/code&gt;&amp;nbsp;for magic cell&amp;nbsp;&lt;code&gt;#%ollama&lt;/code&gt;.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;7) Notebook/chatbook session initialization with custom code + personas JSON&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Initialization runs when the extension is loaded.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;A) Custom Raku init code&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Env var override: &lt;code&gt;RAKU_CHATBOOK_INIT_FILE&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;If not set, first existing file is used in this order:&lt;/li&gt;
&lt;/ul&gt;



&lt;ol class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;~/.config/raku-chatbook/init.py&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;~/.config/init.raku&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;p class="wp-block-paragraph"&gt;Use this for imports/helpers you always want in chatbook sessions.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;B) Pre-load personas from JSON&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Env var override: &lt;code&gt;RAKU_CHATBOOK_LLM_PERSONAS_CONF&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;If not set, first existing file is used in this order:&lt;/li&gt;
&lt;/ul&gt;



&lt;ol class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;~/.config/raku-chatbook/llm-personas.json&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;~/.config/llm-personas.json&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;p class="wp-block-paragraph"&gt;The supported JSON shape is an array of dictionaries:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;[&lt;/div&gt;&lt;div class="cm-line"&gt;  {&lt;/div&gt;&lt;div class="cm-line"&gt;    &amp;quot;chat-id&amp;quot;: &amp;quot;raku&amp;quot;,&lt;/div&gt;&lt;div class="cm-line"&gt;    &amp;quot;conf&amp;quot;: &amp;quot;ChatGPT&amp;quot;,&lt;/div&gt;&lt;div class="cm-line"&gt;    &amp;quot;prompt&amp;quot;: &amp;quot;@CodeWriterX|Raku&amp;quot;,&lt;/div&gt;&lt;div class="cm-line"&gt;    &amp;quot;model&amp;quot;: &amp;quot;gpt-4.1-mini&amp;quot;,&lt;/div&gt;&lt;div class="cm-line"&gt;    &amp;quot;max_tokens&amp;quot;: 8192,&lt;/div&gt;&lt;div class="cm-line"&gt;    &amp;quot;temperature&amp;quot;: 0.4&lt;/div&gt;&lt;div class="cm-line"&gt;  }&lt;/div&gt;&lt;div class="cm-line"&gt;]&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Recognized persona spec fields include:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;chat-id&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;prompt&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;conf&lt;/code&gt; (or &lt;code&gt;configuration&lt;/code&gt;)&lt;/li&gt;



&lt;li&gt;&lt;code&gt;model&lt;/code&gt;, &lt;code&gt;max-tokens&lt;/code&gt;, &lt;code&gt;temperature&lt;/code&gt;, &lt;code&gt;base-url&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;api-key&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;evaluator-args&lt;/code&gt; (object)&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;Verify pre-loaded personas:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%chat all&lt;/div&gt;&lt;div class="cm-line"&gt;keys&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Quick reference for the Raku package "Jupyter::Chatbook".</div>
    </summary>
    <author>
      <name>Anton Antonov Antonov</name>
    </author>
    <id>http://rakuforprediction.wordpress.com/?p=1700</id>
    <published>2026-03-14T13:50:52Z</published>
    <updated>2026-03-14T13:50:52Z</updated>
    <category term="Chatbooks"/>
    <category term="Gemini"/>
    <category term="Generative Art"/>
    <category term="Jupyter"/>
    <category term="Jupyter kernel"/>
    <category term="Large Language Models"/>
    <category term="Literate Programming"/>
    <category term="LLaMA"/>
    <category term="Markdown"/>
    <category term="Natural Language Processing"/>
    <category term="OpenAI"/>
    <category term="Raku"/>
    <category term="Web API"/>
    <category term="Workflow"/>
    <category term="ChatGPT"/>
    <category term="LLM"/>
    <category term="NLP"/>
  </entry>
  <entry>
    <title>CragCLI</title>
    <link rel="alternate" href="https://rakujourney.wordpress.com/2026/03/10/cragcli/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p class="wp-block-paragraph">A <a href="https://cragcli.info">Calculator</a> for the Command Line, that grabs data directly from AI.</p>



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



<p class="wp-block-paragraph">You are a command line user, perhaps a software developer,  a data scientist or an IT savvy engineer.</p>



<p class="wp-block-paragraph">You are a numerate person, who likes to know the numbers behind what you see.</p>



<p class="wp-block-paragraph">You often reach for a calculator. You are comfortable driving a scientific calculator. Maybe you already use another command line calculator like <code>bc</code>.</p>



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



<p class="wp-block-paragraph"><a href="https://cragcli.info">CragCLI</a> is right there.</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">&gt; crag '0.1+0.2'     #output 0.3</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">It does two things.</p>



<p class="wp-block-paragraph">Text based scientific calculator….</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">Arithmetic, Functions, Logs, Trig, Complex, Random, Memory, Types, Rounding</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">…with next level features, such as <em>artificial intelligence</em> and <em>dimensional analysis</em>[1]. </p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">LLM, SIUnits, NonSI, Time, Data, Currency, Angles, Conversions, Errors, </div><div class="cm-line">Constants, Colors, Sequences, Bases, Bitwise, Unicode, Theory</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">CragCLI also provides an <strong><em>interactive mode</em></strong> via a REPL[2].</p>



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



<p class="wp-block-paragraph">Visit the <a href="https://cragcli.info">CragCLI</a> website to see the interactive mode in action and follow the Getting Started instructions.</p>



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



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



<p class="wp-block-paragraph">By the time I read <a href="https://buttondown.com/hillelwayne/archive/raku-a-language-for-gremlins/">Raku: A Language for Gremlins</a>, the idea for Crag had been simmering away. Here’s what Hillel Wayne has to say:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">I finally checked it out last week to see if it’d make a good “calculator language”. I use a hodgepodge of Python, <a href="https://hillelwayne.com/post/j-notation/">J</a>, <a href="https://hillelwayne.com/post/frink/">Frink</a>, and Excel to do math and they all have their own big drawbacks, so it’d be nice if Raku could round them out.</p>



<p class="wp-block-paragraph">After several days of experiments, I’m at a loss of how to describe Raku. The best I can come up with is that the language was designed by a bunch of really intelligent gremlins. Gremlins who spent a lot of time gathering feedback from other gremlins.</p>
</blockquote>



<p class="wp-block-paragraph">That lead me to Frink.  It was a pleasant surprise for me to learn that there are other Gremlins out there, not just me.</p>



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



<p class="wp-block-paragraph">My way in to Raku was to implement a couple of modules – plenty of OO and Grammar learnings and a reflection of my physics mindset.</p>



<ul class="wp-block-list">
<li><a href="https://raku.land/zef:librasteve/Physics::Unit">Physics::Unit</a> – a set of stock SI, Imperial and US Unit objects</li>



<li><a href="https://raku.land/zef:librasteve/Physics::Measure">Physics::Measure</a> – objects that have value, units and error</li>
</ul>



<p class="wp-block-paragraph">These were already done when Hillel piped up.</p>



<h3 class="wp-block-heading">LLM::Functions</h3>



<p class="wp-block-paragraph">This Raku <a href="https://raku.land/zef:antononcube/LLM::Functions">package</a> provides functions and function objects to access, interact, and utilize Large Language Models (LLMs), likeOpenAI, Gemini, MistralAI, and Ollama.</p>



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



<p class="wp-block-paragraph">Since CragCLI uses many Raku modules, credit is due to all the individual authors and contributors of those. More details in the <a href="https://github.com/librasteve/raku-App-Crag">App::Crag</a> repository.</p>



<ul class="wp-block-list">
<li><a href="https://github.com/librasteve/raku-Physics-Measure.git">https://github.com/librasteve/raku-Physics-Measure.git</a></li>



<li><a href="https://github.com/librasteve/raku-Physics-Unit.git">https://github.com/librasteve/raku-Physics-Unit.git</a></li>



<li><a href="https://github.com/librasteve/raku-Physics-Error.git">https://github.com/librasteve/raku-Physics-Error.git</a></li>



<li><a href="https://github.com/librasteve/raku-Physics-Constants.git">https://github.com/librasteve/raku-Physics-Constants.git</a></li>



<li><a href="https://github.com/raku-community-modules/Slang-Roman">https://github.com/raku-community-modules/Slang-Roman</a></li>



<li><a href="https://github.com/bduggan/raku-llm-dwim">https://github.com/bduggan/raku-llm-dwim</a></li>



<li><a href="https://github.com/antononcube/Raku-Math-NumberTheory">https://github.com/antononcube/Raku-Math-NumberTheory</a></li>



<li><a href="https://github.com/raku-community-modules/Color">https://github.com/raku-community-modules/Color</a></li>



<li><a href="https://github.com/holli-holzer/perl6-Color-Names">https://github.com/holli-holzer/perl6-Color-Names</a></li>
</ul>



<p class="wp-block-paragraph">While there are too many contributors to these tools to list them all, I would like to highlight:</p>



<ul class="wp-block-list">
<li><em>Anton Antonov, Brian Duggan, Elizabeth Mattijsen and Holli Holzer.</em></li>
</ul>



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



<p class="wp-block-paragraph">All feedback is welcome, in the comments below or make an Issue on the App::Crag repo.</p>



<p class="wp-block-paragraph">All done in a spirit of -Ofun.</p>



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



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



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



<p class="wp-block-paragraph">[1] Dimensional Analysis is a method of checking or deriving relationships between physical quantities by comparing their fundamental dimensions (such as mass, length, and time).</p>



<p class="wp-block-paragraph">[2] REPL is an interactive programming environment that repeatedly Reads user input, Evaluates it, Prints the result, and Loops to wait for the next command.</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">A Calculator for the Command Line, that grabs data directly from AI. Who You are a command line user, perhaps a software developer, a data scientist or an IT savvy engineer. You are a numerate person, who likes to know the numbers behind what you see. You often reach for a calculator. You are comfortable […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakujourney.wordpress.com/?p=1846</id>
    <published>2026-03-10T11:15:42Z</published>
    <updated>2026-03-10T11:15:42Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>Salvo Combat Modeling: Battle of Coronel</title>
    <link rel="alternate" href="https://rakuforprediction.wordpress.com/2026/03/01/salvo-combat-modeling-battle-of-coronel/" type="text/html"/>
    <content type="html">
&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Introduction&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;In this blog post (&lt;a href="https://github.com/antononcube/Raku-Math-SalvoCombatModeling/blob/main/docs/Battle-of-Coronel.ipynb"&gt;notebook&lt;/a&gt;) we calibrate the Heterogeneous Salvo Combat Model (HSCM), [MJ1, AAp1, AAp2], to the First World War &lt;a href="https://en.wikipedia.org/wiki/Battle_of_Coronel" target="_blank" rel="noreferrer noopener"&gt;Battle of Coronel&lt;/a&gt;, [Wk1]. Our goal is to exemplify the usage of the functionalities of the package &lt;a href="https://raku.land/zef:antononcube/Math::SalvoCombatModeling" target="_blank" rel="noreferrer noopener"&gt;&amp;#8220;Math::SalvoCombatModeling&amp;#8221;&lt;/a&gt;, [AAp1]. We closely follow the Section B of Chapter III of [MJ1]. The calibration data used in [MJ1] is taken from [TB1].&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt; The implementation of the Raku package &lt;a href="https://raku.land/zef:antononcube/Math::SalvoCombatModeling" target="_blank" rel="noreferrer noopener"&gt;&amp;#8220;Math::SalvoCombatModeling&amp;#8221;&lt;/a&gt;, [AAp1], closely follows the implementation of the Wolfram Language (WL) paclet &lt;a href="https://resources.wolframcloud.com/PacletRepository/resources/AntonAntonov/SalvoCombatModeling" target="_blank" rel="noreferrer noopener"&gt;&amp;#8220;SalvoCombatModeling&amp;#8221;&lt;/a&gt;, [AAp2]. Since WL has (i) symbolic builtin computations and (ii) a mature notebook system the salvo models computation, representation, and study with WL is much more convenient.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Setup&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here we load the package:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;use Math::SalvoCombatModeling;&lt;/div&gt;&lt;div class="cm-line"&gt;use Graph;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;The battle&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://en.wikipedia.org/wiki/Battle_of_Coronel"&gt;The Battle of Coronel&lt;/a&gt;&amp;nbsp;is a First World War naval engagement between three British ships {Good Hope, Monmouth, and Glasgow) and four German ships (Scharnhorst, Gneisenau, Leipzig, and Dresden). The battle happened on 1 November 1914, off the coast of central Chile near the city of Coronel.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The Scharnhorst and Gneisenau are the first ships to open fire at Good Hope and Monmouth; the three British ships soon afterwards return fire. Dresden and Leipzig open fire on Glasgow, driving her out of the engagement. At the end of the battle, both Good Hope and Monmouth are sunk, while Glasgow, Scharnhorst, and Gneisenau were damaged.&lt;/p&gt;



&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Ship&lt;/th&gt;&lt;th&gt;Duration of fire&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Good Hope&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Monmouth&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Glasgow&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Scharnhorst&lt;/td&gt;&lt;td&gt;28&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Gneisenau&lt;/td&gt;&lt;td&gt;28&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Leipzig&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dresden&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;The following graph shows which ship shot at which ships and total fire duration (in minutes):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% html&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;my @edges = &lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Scharnhorst&amp;apos;, to =&amp;gt;&amp;apos;Good Hope&amp;apos;,   weight =&amp;gt; 28 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Scharnhorst&amp;apos;, to =&amp;gt;&amp;apos;Monmouth&amp;apos;,    weight =&amp;gt; 28 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Gneisenau&amp;apos;,   to =&amp;gt;&amp;apos;Good Hope&amp;apos;,   weight =&amp;gt; 28 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Gneisenau&amp;apos;,   to =&amp;gt;&amp;apos;Monmouth&amp;apos;,    weight =&amp;gt; 28 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Leipzig&amp;apos;,     to =&amp;gt;&amp;apos;Glasgow&amp;apos;,     weight =&amp;gt; 2 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Glasgow&amp;apos;,     to =&amp;gt;&amp;apos;Scharnhorst&amp;apos;, weight =&amp;gt; 2 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Glasgow&amp;apos;,     to =&amp;gt;&amp;apos;Gneisenau&amp;apos;,   weight =&amp;gt; 15 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Glasgow&amp;apos;,     to =&amp;gt;&amp;apos;Leipzig&amp;apos;,     weight =&amp;gt; 15 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Glasgow&amp;apos;,     to =&amp;gt;&amp;apos;Dresden&amp;apos;,     weight =&amp;gt; 15 },&lt;/div&gt;&lt;div class="cm-line"&gt;{ from =&amp;gt;&amp;apos;Dresden&amp;apos;,     to =&amp;gt;&amp;apos;Glasgow&amp;apos;,     weight =&amp;gt; 15 };&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;my $g = Graph.new(@edges):directed;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;$g.dot(&lt;/div&gt;&lt;div class="cm-line"&gt;    engine =&amp;gt; &amp;apos;neato&amp;apos;, &lt;/div&gt;&lt;div class="cm-line"&gt;    vertex-shape =&amp;gt; &amp;apos;ellipse&amp;apos;, &lt;/div&gt;&lt;div class="cm-line"&gt;    vertex-width =&amp;gt; 0.65,&lt;/div&gt;&lt;div class="cm-line"&gt;    :5size, &lt;/div&gt;&lt;div class="cm-line"&gt;    :8vertex-font-size, &lt;/div&gt;&lt;div class="cm-line"&gt;    :weights, &lt;/div&gt;&lt;div class="cm-line"&gt;    :6edge-font-size,&lt;/div&gt;&lt;div class="cm-line"&gt;    edge-thickness =&amp;gt; 0.8,&lt;/div&gt;&lt;div class="cm-line"&gt;    arrow-size =&amp;gt; 0.6&lt;/div&gt;&lt;div class="cm-line"&gt;):svg;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image size-full is-resized"&gt;&lt;a href="https://raw.githubusercontent.com/antononcube/RakuForPrediction-blog/0c2e92d78e0de60c9437b1760c3262b9c490cd77/Articles/Diagrams/Salvo-combat-modeling-Battle-of-Coronel/Battle-of-Coronel-ship-attacks-graph.svg" target="_blank" rel=" noreferrer noopener"&gt;&lt;img data-attachment-id="1689" data-permalink="https://rakuforprediction.wordpress.com/2026/03/01/salvo-combat-modeling-battle-of-coronel/battle-of-coronel-ship-attacks-graph-light/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png" data-orig-size="944,756" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Battle-of-Coronel-ship-attacks-graph-light" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png?w=944" loading="lazy" width="944" height="756" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png" alt="" class="wp-image-1689" style="aspect-ratio:1.2487224751463346;width:598px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png 944w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png?w=150&amp;amp;h=120 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png?w=300&amp;amp;h=240 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-ship-attacks-graph-light.png?w=768&amp;amp;h=615 768w" sizes="(max-width: 944px) 100vw, 944px" /&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Salvo combat modeling definitions&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Before going with building the model here is table that provides definitions of the fundamental notions of salvo combat modeling:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% html&lt;/div&gt;&lt;div class="cm-line"&gt;salvo-notion-definitions(&amp;apos;English&amp;apos;)&lt;/div&gt;&lt;div class="cm-line"&gt;==&amp;gt; to-html(field-names =&amp;gt; &amp;lt;notion definition&amp;gt;, align =&amp;gt; &amp;apos;left&amp;apos;)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;notion&lt;/th&gt;&lt;th&gt;definition&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Force&lt;/td&gt;&lt;td&gt;A group of naval ships that operate and fight together.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Unit&lt;/td&gt;&lt;td&gt;A unit is an individual ship in a force.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Salvo&lt;/td&gt;&lt;td&gt;A salvo is the number of shots fired as a unit of force in a discrete period of time.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Combat Potential&lt;/td&gt;&lt;td&gt;Combat Potential is a force&amp;#8217;s total stored offensive capability of an element or force measured in number of total shots available.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Combat Power&lt;/td&gt;&lt;td&gt;Also called Striking Power, is the maximum offensive capability of an element or force per salvo, measured in the number of hitting shots that would be achieved in the absence of degrading factors.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Scouting Effectiveness&lt;/td&gt;&lt;td&gt;Scouting Effectiveness is a dimensionless degradation factor applied to a force&amp;#8217;s combat power as a result of imperfect information. It is a number between zero and one that describes the difference between the shots delivered based on perfect knowledge of enemy composition and position and shots based on existing information [Ref. 7].&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Training Effectiveness&lt;/td&gt;&lt;td&gt;Training effectiveness is a fraction that indicates the degradation in combat power due the lack of training, motivation, or readiness.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Distraction Factor&lt;/td&gt;&lt;td&gt;Also called chaff effectiveness or seduction, is a multiplier that describes the effectiveness of an offensive weapon in the presence of distraction or other soft kill. This multiplier is a fraction, where one indicates no susceptibility/complete effectiveness and zero indicates complete susceptibility/no effectiveness.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Offensive Effectiveness&lt;/td&gt;&lt;td&gt;Offensive effectiveness is a composite term made of the product of scouting effectiveness, training effectiveness, distraction, or any other factor which represents the probability of a single salvo hitting its target. Offensive effectiveness transforms a unit&amp;#8217;s combat potential parameter into combat power.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Defensive Potential&lt;/td&gt;&lt;td&gt;Defensive potential is a force&amp;#8217;s total defensive capability measured in units of enemy hits eliminated independent of weapon system or operator accuracy or any other multiplicative factor.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Defensive Power&lt;/td&gt;&lt;td&gt;Defensive power is the number of missiles in an enemy salvo that a defending element or force can eliminate.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Defender Alertness&lt;/td&gt;&lt;td&gt;Defender alertness is the extent to which a defender fails to take proper defensive actions against enemy fire. This may be the result of any inattentiveness due to improper emission control procedures, readiness, or other similar factors. This multiplier is a fraction, where one indicates complete alertness and zero indicates no alertness.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Defensive Effectiveness&lt;/td&gt;&lt;td&gt;Defensive effectiveness is a composite term made of the product of training effectiveness and defender alertness. This term also applies to any value that represents the overall degradation of a force&amp;#8217;s defensive power.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Staying Power&lt;/td&gt;&lt;td&gt;Staying power is the number of hits that a unit or force can absorb before being placed out of action.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Model&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;The British ships are in&amp;nbsp;&lt;em&gt;Good Hope&lt;/em&gt;,&amp;nbsp;&lt;em&gt;Monmouth&lt;/em&gt;, and&amp;nbsp;&lt;em&gt;Glasgow&lt;/em&gt;. They correspond to the indices 1, ,2, and 3 respectively.&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;[&amp;quot;Good Hope&amp;quot;, &amp;quot;Monmouth&amp;quot;, &amp;quot;Glasgow&amp;quot;] Z=&amp;gt; 1..3&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# (Good Hope =&amp;gt; 1 Monmouth =&amp;gt; 2 Glasgow =&amp;gt; 3)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;The German ships are&amp;nbsp;&lt;em&gt;Scharnhorst&lt;/em&gt;,&amp;nbsp;&lt;em&gt;Gneisenau&lt;/em&gt;,&amp;nbsp;&lt;em&gt;Leipzig&lt;/em&gt;, and&amp;nbsp;&lt;em&gt;Dresden&lt;/em&gt;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;[&amp;quot;Scharnhorst&amp;quot;, &amp;quot;Gneisenau&amp;quot;, &amp;quot;Leipzig&amp;quot;,  &amp;quot;Dresden&amp;quot;] Z=&amp;gt; 1..4&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# (Scharnhorst =&amp;gt; 1 Gneisenau =&amp;gt; 2 Leipzig =&amp;gt; 3 Dresden =&amp;gt; 4)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;The&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Battle_of_Coronel"&gt;Battle of Coronel&lt;/a&gt;&amp;nbsp;is modeled with a &amp;#8220;typical&amp;#8221; salvo model &amp;#8212; the ships use &amp;#8220;continuous fire.&amp;#8221; Hence, there are no interceptors and or, in model terms, defense terms or matrices.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Here is the model (for 3&amp;nbsp;&lt;strong&gt;B&lt;/strong&gt;ritish ships and 4&amp;nbsp;&lt;strong&gt;G&lt;/strong&gt;erman ships):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sink my $m = heterogeneous-salvo-model([&amp;apos;B&amp;apos;, 3], [&amp;apos;G&amp;apos;, 4]):latex;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Remove the defense matrices (i.e. make them zero):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sink $m&amp;lt;B&amp;gt;&amp;lt;defense-matrix&amp;gt; = ((0 xx $m&amp;lt;B&amp;gt;&amp;lt;defense-matrix&amp;gt;.head.elems).Array xx $m&amp;lt;B&amp;gt;&amp;lt;defense-matrix&amp;gt;.elems).Array;&lt;/div&gt;&lt;div class="cm-line"&gt;sink $m&amp;lt;G&amp;gt;&amp;lt;defense-matrix&amp;gt; = ((0 xx $m&amp;lt;G&amp;gt;&amp;lt;defense-matrix&amp;gt;.head.elems).Array xx $m&amp;lt;G&amp;gt;&amp;lt;defense-matrix&amp;gt;.elems).Array;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Converting the obtained model data structure to LaTeX we get:&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;a href="https://raw.githubusercontent.com/antononcube/RakuForPrediction-blog/refs/heads/main/Articles/Diagrams/Salvo-combat-modeling-Battle-of-Coronel/Battle-of-Coronel-model-LaTeX-form.png" target="_blank" rel=" noreferrer noopener"&gt;&lt;img data-attachment-id="1696" data-permalink="https://rakuforprediction.wordpress.com/2026/03/01/salvo-combat-modeling-battle-of-coronel/battle-of-coronel-model-latex-form/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png" data-orig-size="3321,948" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Battle-of-Coronel-model-LaTeX-form" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=1008" loading="lazy" width="1024" height="292" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=1024" alt="" class="wp-image-1696" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=1024 1024w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=2048 2048w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=300 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=768 768w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/battle-of-coronel-model-latex-form.png?w=1440 1440w" sizes="(max-width: 1024px) 100vw, 1024px" /&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;h4 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Concrete parameter values&lt;/h4&gt;



&lt;p class="wp-block-paragraph"&gt;Setting the parameter values as in [MJ1] defining the sub&amp;nbsp;&lt;code&gt;param&lt;/code&gt;&amp;nbsp;(to be passed&amp;nbsp;&lt;code&gt;heterogeneous-salvo-model&lt;/code&gt;):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;multi sub param(Str:D $name, Str:D $a where * eq &amp;apos;B&amp;apos;, Str:D $b where * eq &amp;apos;G&amp;apos;, UInt:D $i, UInt:D $j) { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;multi sub param(Str:D $name, Str:D $a where * eq &amp;apos;G&amp;apos;, Str:D $b where * eq &amp;apos;B&amp;apos;, UInt:D $i, UInt:D $j) {&lt;/div&gt;&lt;div class="cm-line"&gt;    given $name {&lt;/div&gt;&lt;div class="cm-line"&gt;        when &amp;apos;beta&amp;apos; {&lt;/div&gt;&lt;div class="cm-line"&gt;            given ($i, $j) {&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 1) { 2.16 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 2) { 2.16 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 3) { 2.16 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 1) { 2.16 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 2) { 2.16 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 3) { 2.16 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 1) { 2.165 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 2) { 2.165 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 3) { 2.165 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 1) { 2.165 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 2) { 2.165 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 3) { 2.165 }&lt;/div&gt;&lt;div class="cm-line"&gt;            }&lt;/div&gt;&lt;div class="cm-line"&gt;        }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;        when &amp;apos;curlyepsilon&amp;apos; {&lt;/div&gt;&lt;div class="cm-line"&gt;            given ($i, $j) {&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 1) { 0.028 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 2) { 0.028 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 3) { 0.028 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 1) { 0.028 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 2) { 0.028 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 3) { 0.028 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 1) { 0.012 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 2) { 0.012 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 3) { 0.012 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 1) { 0.012 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 2) { 0.012 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 3) { 0.012 }&lt;/div&gt;&lt;div class="cm-line"&gt;            }&lt;/div&gt;&lt;div class="cm-line"&gt;        }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;        when &amp;apos;capitalpsi&amp;apos; {&lt;/div&gt;&lt;div class="cm-line"&gt;            given ($i, $j) {&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 1) { 0.5 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 2) { 0.5 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 1) { 0.5 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 2) { 0.5 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 1) { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 2) { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 1) { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 2) { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;                when (1, 3) { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (2, 3) { 0 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (3, 3) { 1 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when (4, 3) { 1 }&lt;/div&gt;&lt;div class="cm-line"&gt;            }&lt;/div&gt;&lt;div class="cm-line"&gt;        }&lt;/div&gt;&lt;div class="cm-line"&gt;    }&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;multi sub param(Str:D $name, Str:D $a where * eq &amp;apos;G&amp;apos;, UInt:D $i) { 1 }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;multi sub param(Str:D $name, Str:D $a where * eq &amp;apos;B&amp;apos;, UInt:D $i) {&lt;/div&gt;&lt;div class="cm-line"&gt;    given $name {&lt;/div&gt;&lt;div class="cm-line"&gt;        when &amp;apos;zeta&amp;apos; {&lt;/div&gt;&lt;div class="cm-line"&gt;            given $i {&lt;/div&gt;&lt;div class="cm-line"&gt;                when 1 { 1.605 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when 2 { 1.605 }&lt;/div&gt;&lt;div class="cm-line"&gt;                when 3 { 1.23 }&lt;/div&gt;&lt;div class="cm-line"&gt;            }&lt;/div&gt;&lt;div class="cm-line"&gt;        }&lt;/div&gt;&lt;div class="cm-line"&gt;    }&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;multi sub param(Str:D $name where $name eq &amp;apos;units&amp;apos;, Str:D $a where * eq &amp;apos;B&amp;apos;, UInt:D $i) { $i }&lt;/div&gt;&lt;div class="cm-line"&gt;multi sub param(Str:D $name where $name eq &amp;apos;units&amp;apos;, Str:D $a where * eq &amp;apos;G&amp;apos;, UInt:D $i) { $i }&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# &amp;amp;param&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Damage calculations&lt;/h3&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $m = heterogeneous-salvo-model([&amp;apos;B&amp;apos;, 3], [&amp;apos;G&amp;apos;, 4], :offensive-effectiveness-terms, :&amp;amp;param)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# {B =&amp;gt; {defense-matrix =&amp;gt; [[0 0 0] [0 0 0] [0 0 0]], offense-matrix =&amp;gt; [[0.018841 0.018841 0 0] [0.018841 0.018841 0 0] [0 0 0.021122 0.021122]], units =&amp;gt; [1 2 3]}, G =&amp;gt; {defense-matrix =&amp;gt; [[0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0]], offense-matrix =&amp;gt; [[0 0 0] [0 0 0] [0 0 0] [0 0 0]], units =&amp;gt; [1 2 3 4]}}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;$m&amp;lt;B&amp;gt;&amp;lt;offense-matrix&amp;gt;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# [[0.018841 0.018841 0 0] [0.018841 0.018841 0 0] [0 0 0.021122 0.021122]]&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $ΔB = $m&amp;lt;B&amp;gt;&amp;lt;offense-matrix&amp;gt;».sum&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# (0.037682 0.037682 0.042244)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;How many salvos to achieve total damage of Good Hope and Monmouth:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;1 / $ΔB.head&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 26.537698&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;That is close to the 28 min of fire by Scharnhorst and Gneisenau at Good Hope and Monmouth.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Total damage of on Glasgow &amp;#8212; Leipzig and Dresden fire for 2 min at Glasgow:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;$ΔB.tail * 2&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 0.084488&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;References&lt;/h2&gt;



&lt;h4 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Articles, theses&lt;/h4&gt;



&lt;p class="wp-block-paragraph"&gt;[MJ1] Michael D. Johns, Steven E. Pilnick, Wayne P. Hughes,&amp;nbsp;&lt;a href="https://apps.dtic.mil/sti/citations/ADA386434"&gt;&amp;#8220;Heterogeneous Salvo Model for the Navy After Next&amp;#8221;&lt;/a&gt;, (2000), Defense Technical Information Center.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[TB1] Thomas R. Beall,&amp;nbsp;&lt;a href="https://apps.dtic.mil/sti/citations/ADA226615"&gt;&amp;#8220;The Development of a Naval Battle Model and Its Validation Using Historical Data&amp;#8221;&lt;/a&gt;, (1990), Defense Technical Information Center.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[Wk1] Wikipedia entry,&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Salvo_combat_model"&gt;Salvo combat model&lt;/a&gt;.&lt;/p&gt;



&lt;h4 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Packages, paclets&lt;/h4&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp1] Anton Antonov,&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/Math::SalvoCombatModeling"&gt;Math::SalvoCombatModeling, Raku package&lt;/a&gt;, (2026),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHib/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp2] Anton Antonov,&amp;nbsp;&lt;a href="https://resources.wolframcloud.com/PacletRepository/resources/AntonAntonov/SalvoCombatModeling/"&gt;SalvoCombatModeling, Wolfram Language paclet&lt;/a&gt;, (2024), Wolfram Language Paclet Repository.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img data-attachment-id="1693" data-permalink="https://rakuforprediction.wordpress.com/2026/03/01/salvo-combat-modeling-battle-of-coronel/die_seeschlacht_bei_coronel-_gemalde_gemini-1-battle/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png" data-orig-size="1584,586" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Die_Seeschlacht_bei_Coronel._Gemälde_Gemini-1-battle" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=1008" loading="lazy" width="1024" height="378" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=1024" alt="" class="wp-image-1693" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=1024 1024w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=300 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=768 768w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png?w=1440 1440w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/03/die_seeschlacht_bei_coronel._gemalde_gemini-1-battle.png 1584w" sizes="(max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">In this blog post (notebook) we calibrate the Heterogeneous Salvo Combat Model (HSCM), to the First World War Battle of Coronel. Our goal is to exemplify the usage of the functionalities of the Raku package  "Math::SalvoCombatModeling".</div>
    </summary>
    <author>
      <name>Anton Antonov Antonov</name>
    </author>
    <id>http://rakuforprediction.wordpress.com/?p=1687</id>
    <published>2026-03-01T17:28:45Z</published>
    <updated>2026-03-01T17:28:45Z</updated>
    <category term="Gemini"/>
    <category term="Generative Art"/>
    <category term="Graphs"/>
    <category term="Graphviz"/>
    <category term="Mathematical Modeling"/>
    <category term="Salvo Combat Modeling"/>
    <category term="Uncategorized"/>
    <category term="Jupyter"/>
    <category term="Raku"/>
  </entry>
  <entry>
    <title>Day 16 – Post Removed</title>
    <link rel="alternate" href="https://raku-advent.blog/2026/02/28/day-16-post-removed/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p class="has-text-align-center has-large-font-size wp-block-paragraph">This blog post has been removed because of legal reasons by request of the author.</p>



<p class="wp-block-paragraph"/>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This blog post has been removed because of legal reasons by request of the author.</div>
    </summary>
    <author>
      <name>Elizabeth Mattijsen</name>
    </author>
    <id>http://raku-advent.blog/?p=4526</id>
    <published>2026-02-28T13:20:43Z</published>
    <updated>2026-02-28T13:20:43Z</updated>
    <category term="2025"/>
  </entry>
  <entry>
    <title> Rakudo compiler, Release #190 (2026.02)</title>
    <link rel="alternate" href="https://rakudo.org/post/announce-rakudo-release-2026.02" type="text/html"/>
    <id>https://rakudo.org/post/announce-rakudo-release-2026.02</id>
    <published>2026-02-28T00:00:00Z</published>
    <updated>2026-02-28T00:00:00Z</updated>
  </entry>
  <entry>
    <title>Definitely How What Where, Who?</title>
    <link rel="alternate" href="https://dev.to/lizmat/definitely-how-what-where-who-5c5n" type="text/html"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;This is part thirteen in the &lt;a href="https://dev.to/lizmat/series/35190"&gt;"Cases of UPPER"&lt;/a&gt; series of blog posts, describing the Raku syntax elements that are completely in UPPERCASE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This part will discuss the various introspection methods that you can use on objects in the &lt;a href="https://raku.org" rel="noopener noreferrer"&gt;Raku Programming Language&lt;/a&gt;.  Note that in some documentation these methods are also referred to as &lt;a href="https://docs.raku.org/language/mop#Metamethods" rel="noopener noreferrer"&gt;Metamethods&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turtles All The Way Down
&lt;/h2&gt;

&lt;p&gt;In Raku everything is an object, or can be thought of as an object.  An object is an instantiation of a class (usually made by calling the &lt;code&gt;new&lt;/code&gt; method on it).  A class is represented by a so-called &lt;a href="https://docs.raku.org/language/objects#Type_objects" rel="noopener noreferrer"&gt;"type object"&lt;/a&gt;.  Such a type object in turn is an instantation of a so-called &lt;a href="https://docs.raku.org/language/mop" rel="noopener noreferrer"&gt;meta class&lt;/a&gt;.  And these meta classes are themselves built out of more primitive representations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Going this deep would most definitely be out of scope for these blog posts.  But yours truly does intend to go there at some point in the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  WHAT
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.raku.org/syntax/WHAT" rel="noopener noreferrer"&gt;&lt;code&gt;WHAT&lt;/code&gt;&lt;/a&gt; method returns the &lt;a href="https://docs.raku.org/syntax/type%20object" rel="noopener noreferrer"&gt;type object&lt;/a&gt; of the given invocant.  Not much else to tell about it really.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;WHAT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;# (Int)&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;WHAT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# (Str)&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;WHAT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;# (Instant)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  HOW
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.raku.org/syntax/HOW" rel="noopener noreferrer"&gt;&lt;code&gt;HOW&lt;/code&gt;&lt;/a&gt; method returns the meta-object of the class of the given invocant.  The &lt;code&gt;HOW&lt;/code&gt; (b)acronym stands for "&lt;strong&gt;H&lt;/strong&gt;igher &lt;strong&gt;O&lt;/strong&gt;rder &lt;strong&gt;W&lt;/strong&gt;orkings".  It allows one to introspect the class of the invocant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;HOW&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;# Int&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;HOW&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;  &lt;span class="c1"&gt;# Str&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;HOW&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;# Instant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the invocant of the &lt;code&gt;HOW&lt;/code&gt; method needs to be repeated in the introspection method's call as the first argument.  Why?  Well, this is really to be &lt;em&gt;possibly&lt;/em&gt; compatible with &lt;em&gt;future&lt;/em&gt; versions of Raku.&lt;/p&gt;

&lt;p&gt;Since one is usually only interested in the introspection aspect of &lt;code&gt;HOW&lt;/code&gt;, a shortcut method invocation was created that allows one to directly call the introspection method &lt;strong&gt;without&lt;/strong&gt; needing to repeat oneself: &lt;a href="https://docs.raku.org/language/operators#methodop_%2E^" rel="noopener noreferrer"&gt;&lt;code&gt;.^&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;# Int&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# Str&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;# Instant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some other common introspection methods are &lt;a href="https://docs.raku.org/type/Metamodel/C3MRO#method_mro" rel="noopener noreferrer"&gt;&lt;code&gt;mro&lt;/code&gt;&lt;/a&gt; (showing the base classes of the class of the value) and &lt;a href="https://docs.raku.org/routine/methods" rel="noopener noreferrer"&gt;&lt;code&gt;methods&lt;/code&gt;&lt;/a&gt; (which returns the &lt;code&gt;method&lt;/code&gt; objects of the methods that can be called on the value):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;mro&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;           &lt;span class="c1"&gt;# ((Int) (Cool) (Any) (Mu))&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# (ACCEPTS Bool Bridge Capture Complex...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that these meta-classes are classes themselves, so can have meta-methods on them called as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;HOW&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# Perl6::Metamodel::ClassHOW&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Yeah, there's still some legacy code that will need renaming under the hood!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  WHERE
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.raku.org/routine/WHERE" rel="noopener noreferrer"&gt;&lt;code&gt;WHERE&lt;/code&gt;&lt;/a&gt; method returns the memory address of the invocant.  It is of limited use in the Rakudo implementation as the memory location of an object is &lt;strong&gt;not&lt;/strong&gt; guaranteed to be constant.  As such, it is intended for (core) debugging only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;WHERE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# 2912024602280 (or some other number)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  VAR
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/lizmat/store-proxy-fetch-a07"&gt;previous blog post&lt;/a&gt; the &lt;code&gt;Scalar&lt;/code&gt; object was described.  But the &lt;code&gt;Scalar&lt;/code&gt; objects are nearly invisible.  How can one obtain a &lt;code&gt;Scalar&lt;/code&gt; object from a given variable?  And find out its name from that?&lt;/p&gt;

&lt;p&gt;The "secret" to that is the &lt;a href="https://docs.raku.org/syntax/VAR" rel="noopener noreferrer"&gt;&lt;code&gt;VAR&lt;/code&gt;&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;VAR&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# Scalar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;Scalar&lt;/code&gt; object provides at least these &lt;a href="https://docs.raku.org/type/Scalar#Introspection" rel="noopener noreferrer"&gt;introspection methods&lt;/a&gt;: &lt;a href="https://docs.raku.org/type/Scalar#method_of" rel="noopener noreferrer"&gt;&lt;code&gt;of&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.raku.org/type/Scalar#method_name" rel="noopener noreferrer"&gt;&lt;code&gt;name&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.raku.org/type/Scalar#method_default" rel="noopener noreferrer"&gt;&lt;code&gt;default&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.raku.org/type/Scalar#method_dynamic" rel="noopener noreferrer"&gt;&lt;code&gt;dynamic&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;Int&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;# 666&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;VAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;# (Int)&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;VAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;# $a&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;VAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# 42&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;VAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;of&lt;/code&gt; method returns the constraint that needs to be fulfilled in order to be able to assign to the variable.  The &lt;code&gt;name&lt;/code&gt; method returns the name of the variable.  The &lt;code&gt;default&lt;/code&gt; method returns the default value (&lt;code&gt;Any&lt;/code&gt; if none is specified).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;dynamic&lt;/code&gt; method returns &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; whether the variable is visible for dynamic variable lookups.  This usually only returns &lt;code&gt;True&lt;/code&gt; for variables with the &lt;a href="https://docs.raku.org/language/variables#The_*_twigil" rel="noopener noreferrer"&gt;&lt;code&gt;*&lt;/code&gt; twigil&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  WHO
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.raku.org/syntax/WHO" rel="noopener noreferrer"&gt;&lt;code&gt;WHO&lt;/code&gt;&lt;/a&gt; method (for "who lives here?) is actually a bit of a misnomer.  It should probably have been called &lt;code&gt;OUR&lt;/code&gt; because it returns the &lt;a href="https://docs.raku.org/type/Stash" rel="noopener noreferrer"&gt;&lt;code&gt;Stash&lt;/code&gt;&lt;/a&gt; of the type object of the invocant.  And a stash is an object that does the &lt;code&gt;Associative&lt;/code&gt; role, and as such can be accessed as if it were a &lt;code&gt;Hash&lt;/code&gt;.  And the stash of a type object is the same namespace as &lt;code&gt;our&lt;/code&gt; inside that package.&lt;/p&gt;

&lt;p&gt;So for instance if you would like to know all classes that live in the &lt;code&gt;IO&lt;/code&gt; package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;WHO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# (ArgFiles CatHandle Handle Notification Path Pipe Socket Spec Special)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, you would know them more by their complete names such as &lt;code&gt;IO::ArgFiles&lt;/code&gt;, &lt;code&gt;IO::CatHandle&lt;/code&gt;, &lt;code&gt;IO::Handle&lt;/code&gt;, etc.  In fact the &lt;a href="https://docs.raku.org/language/packages#index-entry-::" rel="noopener noreferrer"&gt;&lt;code&gt;::&lt;/code&gt;&lt;/a&gt; delimiter is shortcut for using &lt;code&gt;WHO&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;WHO&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;Handle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# (Handle)&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nn"&gt;IO::&lt;/span&gt;&lt;span class="nv"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;# (Handle)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that goes even further: &lt;code&gt;foo::&lt;/code&gt; is just short for &lt;code&gt;foo.WHO&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nn"&gt;IO::&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# (ArgFiles CatHandle Handle Notification Path Pipe Socket Spec Special)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A little closer to home: how would that look in a package that you define yourself and have an &lt;a href="https://docs.raku.org/syntax/our" rel="noopener noreferrer"&gt;&lt;code&gt;our&lt;/code&gt;&lt;/a&gt; scoped variable in there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;WHO&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$foo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# 42&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nn"&gt;A::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$foo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;# 42&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;A::&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;# 42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The careful reader will have noticed that &lt;a href="https://docs.raku.org/language/packages" rel="noopener noreferrer"&gt;&lt;code&gt;package&lt;/code&gt;&lt;/a&gt; was used in the example.  A very simple reason: &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;role&lt;/code&gt;, &lt;code&gt;grammar&lt;/code&gt; are all just packages with different &lt;code&gt;HOW&lt;/code&gt;s.  And &lt;code&gt;WHO&lt;/code&gt; doesn't care why kind of &lt;code&gt;package&lt;/code&gt; it is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  REPR
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.raku.org/language/traits#is_repr_and_native_representations%2E" rel="noopener noreferrer"&gt;&lt;code&gt;REPR&lt;/code&gt;&lt;/a&gt; method returns the &lt;em&gt;name&lt;/em&gt; of the memory representation of the class of the invocant.  For most of the objects this is "P6opaque".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is basically the representation used by &lt;code&gt;class&lt;/code&gt; and its attribute specifications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href="https://docs.raku.org/language/nativecall" rel="noopener noreferrer"&gt;&lt;code&gt;NativeCall&lt;/code&gt;&lt;/a&gt; module provides a number or alternate memory representations, such as &lt;a href="https://docs.raku.org/language/nativecall#Structs" rel="noopener noreferrer"&gt;&lt;code&gt;CStruct&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.raku.org/language/nativecall#Basic_use_of_pointers" rel="noopener noreferrer"&gt;&lt;code&gt;CPointer&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.raku.org/language/nativecall#CUnions" rel="noopener noreferrer"&gt;&lt;code&gt;Cunion&lt;/code&gt;&lt;/a&gt;.  Native arrays also have a different representation (&lt;code&gt;VMArray&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;REPR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# P6opaque&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;REPR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# VMArray&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a class is defined, it gets the &lt;code&gt;P6opaque&lt;/code&gt; representation by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;Foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;Foo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;REPR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# P6opaque&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Unless one is doing very deep core-ish work, how an object is represented in memory should not be of concern to you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  DEFINITE
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.raku.org/syntax/DEFINITE" rel="noopener noreferrer"&gt;&lt;code&gt;DEFINITE&lt;/code&gt;&lt;/a&gt; method returns either &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt; depending on whether the invocant has a concrete representation.  This is &lt;em&gt;almost always&lt;/em&gt; the same as calling the &lt;a href="https://docs.raku.org/routine/defined" rel="noopener noreferrer"&gt;&lt;code&gt;defined&lt;/code&gt;&lt;/a&gt; method.  But in some cases it makes more sense in Raku to return the opposite with the &lt;code&gt;defined&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;An example of this is the &lt;code&gt;Failure&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;Failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;DEFINITE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# True&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;Failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;# False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In general the &lt;code&gt;defined&lt;/code&gt; method should be used.  The &lt;code&gt;DEFINITE&lt;/code&gt; method is intended to be used in very low-level (core) code.  It's not all uppercase for nothing!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The reason &lt;code&gt;Failure.new.defined&lt;/code&gt; always returns &lt;code&gt;False&lt;/code&gt; is to make it compatible with &lt;a href="https://docs.raku.org/syntax/with%20orwith%20without" rel="noopener noreferrer"&gt;&lt;code&gt;with&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Macroish
&lt;/h2&gt;

&lt;p&gt;All of the introspection "metamethods" described in this blog post are actually parsed as macros directly generating low-level execution opcodes.  This is really necessary in some cases (as otherwise information can be lost), and in other cases it's just for performance.&lt;/p&gt;

&lt;p&gt;This doesn't mean that it's not possible to call this introspection functionality as a method: you can.  For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;macro: &lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;  &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;VAR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;# macro: $a&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;method: &lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VAR&lt;/span&gt;&lt;span class="p"&gt;"()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# method: $a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore for consistency, the same functionality of these methods is &lt;strong&gt;also&lt;/strong&gt; available as subroutines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sub: &lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="nv"&gt;VAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# sub: $b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if you're more at home in imperative programming, you can do that as well!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This concludes the thirteenth episode of cases of UPPER language elements in the Raku Programming Language, the sixth episode discussing interface methods.&lt;/p&gt;

&lt;p&gt;In this episode the following macro-like introspection methods were discussed (in alphabetical order): &lt;code&gt;DEFINITE&lt;/code&gt;, &lt;code&gt;HOW&lt;/code&gt;, &lt;code&gt;REPR&lt;/code&gt;, &lt;code&gt;VAR&lt;/code&gt;, &lt;code&gt;WHAT&lt;/code&gt;, &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;WHO&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

</content>
    <author>
      <name>Elizabeth Mattijsen</name>
    </author>
    <id>https://dev.to/lizmat/definitely-how-what-where-who-5c5n</id>
    <published>2026-02-24T13:29:22Z</published>
    <updated>2026-02-24T13:29:22Z</updated>
    <category term="rakulang"/>
    <category term="programming"/>
    <category term="tutorial"/>
  </entry>
  <entry>
    <title>Raku Resolutions #3</title>
    <link rel="alternate" href="https://dev.to/lizmat/raku-resolutions-3-3j6m" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><blockquote>
<p>This is a third follow-up on <a href="https://dev.to/lizmat/series/34948">Raku Resolutions</a> series.</p>
</blockquote>

<p>The third meeting was held on 21 February 2026 at 19:00 UTC.  Apart from 3 Raku Steering Council members, only 1 other person attended.  In the end, <strong>7</strong> issues were discussed within the allotted time (1 hour).</p>

<h3>
  
  
  <a href="https://github.com/Raku/problem-solving/issues/286" rel="noopener noreferrer">Separate Community Resource page</a>
</h3>

<p>After some discussion, it became clear that this issue basically has gone stale in light of the new raku.org site.  <em>Richard Hainsworth</em> will create a new issue, after which this one can be closed.</p>

<h3>
  
  
  <a href="https://github.com/Raku/problem-solving/issues/501" rel="noopener noreferrer">What makes <code>unit</code> be too late?</a>
</h3>

<p>After some discussion it was agreed that from a language design point of view, it shouldn't really matter when the <code>unit</code> occurs in the code, as long as there's only one of them.  And that the rest of the source would be considered to be part of that scope.</p>

<p>It was agreed that the documentation will describe this future state with the caveat that this is currently not yet the case.  <em>Eric Forste</em> agreed to make a PR accordingly, after which the issue can be closed.</p>

<p>The point of being able to specify an <code>EXPORT</code> sub <em>before</em> a <code>unit</code> would be technically correct, but not very useful in practice as an <code>EXPORT</code> sub usually needs to refer to objects/classes that have already been defined in the code (and thus should logically be positioned <em>after</em> the scope).</p>

<h3>
  
  
  <a href="https://github.com/Raku/problem-solving/issues/160" rel="noopener noreferrer">Errors indexing past the end of a <code>List</code></a>
</h3>

<p>After some discussion it was decided that the current behaviour of returning <code>Nil</code> for <code>List</code> elements beyond the end is correct.  And that returning a <code>Failure</code> for negative index values is the most consistent behaviour, especially in light of <code>Array</code> doing that as well.  So the issue could be closed.</p>

<h3>
  
  
  <a href="https://github.com/Raku/problem-solving/issues/4" rel="noopener noreferrer">Some useful math/statistics functions are missing</a>
</h3>

<p>Consensus was that it would be nice to have all of these math / statistics methods, but that these should live in module land for the foreseeable future.  So the issue could be closed.</p>

<h3>
  
  
  <a href="https://github.com/Raku/problem-solving/issues/5" rel="noopener noreferrer">There's a huge PR/issue deficit in the Rakudo repo</a>
</h3>

<p>It was recognized that there are indeed quite a few open issues in Rakudo (although much less than there have been in the past).  However, there will always be open issues.  And with the current size of the core team, the number of issues will not significantly reduce in the future (with the current rate of new issues coming in).</p>

<p>So it was decided to close the issue as "unresolvable".</p>

<h3>
  
  
  <a href="https://github.com/Raku/problem-solving/issues/6" rel="noopener noreferrer">New named parameters to <code>.classify</code></a>
</h3>

<p>It was decided that the issue has gone a bit stale, and thus ask the OP (Original Poster) whether this should stay open, especially since it was suggested that <code>.classify</code> / <code>.categorize</code> maybe should need an overhaul (at least internally).</p>

<h3>
  
  
  <a href="https://github.com/Raku/problem-solving/issues/59" rel="noopener noreferrer">Need a substitute for Perl 5 <code>die</code> with newline for raising end-user errors?</a>
</h3>

<p>After explaining the esoteric rule in Perl 5 with regards to <code>die</code> with a message with and without a new line, it was agreed that it would be nice to have such a feature.  Especially since at least 2 of the attendees had been using a <code>note $message; exit 1</code> sequence to achieve just that.  Disadvantage to this is that such a sequence can <strong>not</strong> be caught by a <code>CATCH</code>.</p>

<p>After some discussion, a <code>:no-backtrace</code> named argument to <code>die()</code> was suggested, and that the issue could be closed if a Pull Requst had been created for this.  This has since then been implemented in <a href="https://github.com/rakudo/rakudo/pull/6076" rel="noopener noreferrer">#6076</a>, so the issue was closed.</p>

<h2>
  
  
  Next meeting
</h2>

<p>The next meeting will be held at 7 March 2026 at 19:00 UTC (20:00 CET, 14:00 EST, 11:00 PST, 04:00 JST (22 Jan), 06:00 AEST (22 Jan)), and again at a one hour maximum. If not all of these issues have been resolved, they will be moved to a future meeting.</p>

<p>Since Jitsi is still working out so far, the next one will be held at the same URL: <a href="https://meet.jit.si/SpecificRosesEstablishAllegedly" rel="noopener noreferrer">https://meet.jit.si/SpecificRosesEstablishAllegedly</a>. The reason Jitsi was selected, is that it has proven to be working with minimal hassle for at least the Raku Steering Council meetings. As the only thing you need to be able to attend, is a modern browser, a camera, and a microphone. No further installation required.</p>

<p>A new <a href="https://github.com/Raku/problem-solving/issues?q=state%3Aopen%20label%3A%22Next%20Resolutions%20Meeting%22" rel="noopener noreferrer">set of issues</a> has been selected by yours truly (in issue number order, oldest first):</p>

<ul>
<li><a href="https://github.com/Raku/problem-solving/issues/13" rel="noopener noreferrer">Specify rounding mode in CORE</a></li>
<li><a href="https://github.com/Raku/problem-solving/issues/19" rel="noopener noreferrer">Metadata licenses should be required before adding new modules to ecosystem</a></li>
<li><a href="https://github.com/Raku/problem-solving/issues/21" rel="noopener noreferrer">Semantics of coercion type on an <code>rw</code> parameter</a></li>
<li><a href="https://github.com/Raku/problem-solving/issues/24" rel="noopener noreferrer">where blocks vs sub signatures</a></li>
<li><a href="https://github.com/Raku/problem-solving/issues/55" rel="noopener noreferrer">LCM (support <code>Rat</code> and fail on lossy coercion)</a></li>
<li><a href="https://github.com/Raku/problem-solving/issues/63" rel="noopener noreferrer">Should <code>without</code> allow chaining?</a></li>
<li><a href="https://github.com/Raku/problem-solving/issues/91" rel="noopener noreferrer"><code>.raku</code> should be replaced with a pluggable system</a></li>
</ul>

<h2>
  
  
  Preparation
</h2>

<p>Any Raku Community member is welcome to these meetings.  Do you consider yourself a Raku Community member?  You're welcome.  It's as simple as that.</p>

<p>But please make sure you have looked at the issues that will be discussed <strong>before</strong> attending the meeting.  And if you already have any comments to make on these issues, make them with the issue beforehand.</p>

<p>The original contributors to these issues will also be notified (unless they muted themselves from these issues).  We hope that they also will be able to attend.</p>

<h2>
  
  
  Small steps
</h2>

<p>If you consider yourself a Raku Community member, please try to attend!  If anything, it will allow you to put faces to the names that you may be familiar with.</p>

<p>Hope to see you there!</p>

</div>
    </content>
    <author>
      <name>Elizabeth Mattijsen</name>
    </author>
    <id>https://dev.to/lizmat/raku-resolutions-3-3j6m</id>
    <published>2026-02-22T14:23:48Z</published>
    <updated>2026-02-22T14:23:48Z</updated>
    <category term="rakulang"/>
    <category term="programming"/>
  </entry>
  <entry>
    <title>Store Proxy Fetch</title>
    <link rel="alternate" href="https://dev.to/lizmat/store-proxy-fetch-a07" type="text/html"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;This is part twelve in the &lt;a href="https://dev.to/lizmat/series/35190"&gt;"Cases of UPPER"&lt;/a&gt; series of blog posts, describing the Raku syntax elements that are completely in UPPERCASE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This part will discuss the various aspects of containers in the &lt;a href="https://raku.org" rel="noopener noreferrer"&gt;Raku Programming Language&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Containers and binding
&lt;/h2&gt;

&lt;p&gt;This may come as a shock to some, but Raku really &lt;em&gt;only&lt;/em&gt; knows about &lt;strong&gt;binding&lt;/strong&gt; (&lt;code&gt;:=&lt;/code&gt;) values.  Assignment is &lt;a href="https://en.wikipedia.org/wiki/Syntactic_sugar" rel="noopener noreferrer"&gt;syntactic sugar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What?&lt;/p&gt;

&lt;p&gt;Most of the scalar variables that you see in Raku, are really objects that have an attribute to which the value is &lt;em&gt;bound&lt;/em&gt; when you &lt;em&gt;assign&lt;/em&gt; to the variable.  These objects are called &lt;a href="https://docs.raku.org/type/Scalar" rel="noopener noreferrer"&gt;&lt;code&gt;Scalar&lt;/code&gt;&lt;/a&gt; containers, or just short &lt;a href="https://docs.raku.org/language/containers" rel="noopener noreferrer"&gt;"containers"&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In short: &lt;strong&gt;assignment in Raku is binding to an attribute in a &lt;code&gt;Scalar&lt;/code&gt; object&lt;/strong&gt;.  &lt;a href="https://en.wikipedia.org/wiki/Grok#In_computer_programmer_culture" rel="noopener noreferrer"&gt;Grokking&lt;/a&gt; how containers work in Raku (as opposed to many other programming languages) is one of the rites of passage to becoming an experienced and efficient developer in Raku.  It sure was a rite of passage for yours truly!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a simplified representation (almost &lt;a href="https://en.wikipedia.org/wiki/Pseudocode" rel="noopener noreferrer"&gt;pseudocode&lt;/a&gt;) one can think of these &lt;code&gt;Scalar&lt;/code&gt; objects like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;Scalar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;has&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;STORE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;FETCH&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;value&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;And an assignment such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can be thought of as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Scalar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;STORE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and showing the value of a variable (as in &lt;code&gt;say $a&lt;/code&gt;), can be thought of as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;FETCH&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In reality it's of course slightly more complicated, because there are such things as type constraints that can exist on a variable (such as &lt;code&gt;my Int $a&lt;/code&gt;).  And variables may have a default value (as in &lt;code&gt;my $a is default(42)&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This type of information is kept in a so-called "container descriptor", which is considered to be an &lt;a href="https://docs.raku.org/syntax/is%20implementation-detai" rel="noopener noreferrer"&gt;implementation detail&lt;/a&gt; (as in: don't depend on its functionality directly, the interface to it might change at any time).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many shortcuts are made in implementing this, in the interest of performance.  Because assignments are one of the very basic operations in a programming language.  And you want those to be fast!&lt;/p&gt;

&lt;p&gt;As a mental model, this is very useful for understanding quite a few constructs in Raku.&lt;/p&gt;

&lt;h2&gt;
  
  
  Return values
&lt;/h2&gt;

&lt;p&gt;In Raku any value returned at the end of a block (or with the &lt;a href="https://docs.raku.org/syntax/return" rel="noopener noreferrer"&gt;&lt;code&gt;return&lt;/code&gt;&lt;/a&gt; statement) are de-containerized by default.  This means that something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# Cannot modify an immutable Int (42)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will not work.  What if you could return the container from a block?  Then you could just assign to it!  There are indeed two easy ways to return something with the container intact: the &lt;a href="https://docs.raku.org/routine/is%20rw" rel="noopener noreferrer"&gt;&lt;code&gt;is rw&lt;/code&gt;&lt;/a&gt; trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nf"&gt;is&lt;/span&gt; &lt;span class="nf"&gt;rw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# 666&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternately, one can use the &lt;a href="https://docs.raku.org/syntax/return-rw" rel="noopener noreferrer"&gt;&lt;code&gt;return-rw&lt;/code&gt;&lt;/a&gt; statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;rw&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# 666&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feature is for instance used if you want to assign to an array element.  In &lt;a href="https://dev.to/lizmat/positional-methods-439i"&gt;part 9&lt;/a&gt; of this series it was shown that the &lt;code&gt;AT-POS&lt;/code&gt; method is what is being called by postcircumfix &lt;code&gt;[ ]&lt;/code&gt;.  In the core, both the postcircumfix &lt;code&gt;[ ]&lt;/code&gt; operator as well as the underlying &lt;code&gt;AT-POS&lt;/code&gt; method have this trait set for performance (as the &lt;code&gt;return-rw&lt;/code&gt; statement has slightly more overhead).&lt;/p&gt;

&lt;h2&gt;
  
  
  Binding to containers
&lt;/h2&gt;

&lt;p&gt;If an array is initialized with values, it will create containers for each element and put the right value in the right place.  So you cannot only &lt;em&gt;fetch&lt;/em&gt; the values from there, but you can also &lt;em&gt;assign&lt;/em&gt; to these containers.  And it is also possible to &lt;em&gt;bind&lt;/em&gt; such a container to another variable.&lt;/p&gt;

&lt;p&gt;Binding to containers allows for features in Raku that are considered "magic" by some, and maybe "too magic" by others.  They are part of common idioms in the Raku Programming Language.&lt;/p&gt;

&lt;p&gt;For instance: incrementing all values in an array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&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="mi"&gt;4&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="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# [2 3 4 5 6]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The topic variable &lt;code&gt;$_&lt;/code&gt; &lt;strong&gt;binds&lt;/strong&gt; to the elements of the array in a &lt;code&gt;for&lt;/code&gt; loop.  So in each iteration it actually represents the container at that location and can thus be incremented.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;People coming from other languages may think that &lt;code&gt;$_&lt;/code&gt; is a "reference" (or "pointer") to the actual memory location of the element in the array.  This notion is incorrect in Raku.  The topic variable &lt;code&gt;$_&lt;/code&gt; is bound to the &lt;strong&gt;container&lt;/strong&gt; of each element.  The container object itself is completely agnostic as to where it lives.  It's just a simple object that knows how to &lt;code&gt;FETCH&lt;/code&gt; and &lt;code&gt;STORE&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Slices to arrays also return containers.  For instance to increment only the first and last element in an array without knowing its size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&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="mi"&gt;4&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="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;@a&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="o"&gt;*-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# [2 2 3 4 6]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The slice &lt;code&gt;[0, *-1]&lt;/code&gt; produces 2 containers (one for the first element (&lt;code&gt;0&lt;/code&gt;) and one for the last (&lt;code&gt;*-1&lt;/code&gt;).  Only these containers get incremented, thus giving the expected result.&lt;/p&gt;

&lt;p&gt;The same logic applies to the &lt;a href="https://docs.raku.org/routine/values" rel="noopener noreferrer"&gt;&lt;code&gt;values&lt;/code&gt;&lt;/a&gt; in hashes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# {a =&amp;gt; 43, b =&amp;gt; 667}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But binding containers can also be done directly in your code.  A contrived example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# 666&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that by assigning to &lt;code&gt;$b&lt;/code&gt;, you're assiging to the container that lives in &lt;code&gt;$a&lt;/code&gt;.  Because the binding of &lt;code&gt;$b&lt;/code&gt; to &lt;code&gt;$a&lt;/code&gt; effectively aliased the container in &lt;code&gt;$a&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Special containers
&lt;/h2&gt;

&lt;p&gt;In Raku it is possible to assign to elements in an array that do not exist yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;@a&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# [(Any) (Any) (Any) 42]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So there's no container yet the element at index &lt;code&gt;3&lt;/code&gt;.  Yet it is possible to assign to it!  How does that work?&lt;/p&gt;

&lt;p&gt;The secret is really in the "container descriptor".  So let's refine our pseudocode representation of the &lt;code&gt;Scalar&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;Scalar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;has&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;has&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;STORE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;descriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;FETCH&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;value&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;Note that storing a value has now become a little more complicated (&lt;code&gt;$!descriptor.process($value)&lt;/code&gt; rather than just &lt;code&gt;$!value&lt;/code&gt;).  So the descriptor object's &lt;code&gt;process&lt;/code&gt; method takes the value, does what it needs to do with it, and then returns it so that it can be bound to the attribute.&lt;/p&gt;

&lt;p&gt;This descriptor object is typically responsible for remembering the name of the variable, the default type, perform type checking and keep a default value of a container.  And any additional logic that is needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are many different types of container descriptor classes in the Rakudo implementation, all starting with the &lt;code&gt;ContainerDescriptor::&lt;/code&gt; name.  And all are considered to be implementation detail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For instance, when an &lt;code&gt;AT-POS&lt;/code&gt; method is called on a non-existing element in an array, a container with a special type of descriptor is created that "knows" to which &lt;code&gt;Array&lt;/code&gt; it belongs, and at which index it should be stored.  The same is true for the descriptor of the container returned by &lt;code&gt;AT-KEY&lt;/code&gt; (as seen in &lt;a href="https://dev.to/lizmat/associative-methods-2mcl"&gt;part 10&lt;/a&gt;) which knows in which &lt;code&gt;Hash&lt;/code&gt; it should store when assigned to, and what key should be used.&lt;/p&gt;

&lt;p&gt;It's this special behaviour that allows arrays and hashes to really just &lt;a href="https://docs.raku.org/syntax/DWIM" rel="noopener noreferrer"&gt;DWIM&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Action at a distance
&lt;/h2&gt;

&lt;p&gt;These special descriptors of containers for arrays and hashes also introduce an action-at-a-distance feature that you may or may not like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@a&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="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# []&lt;/span&gt;
&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;@a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# [(Any) (Any) (Any) 42]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the element in the array was &lt;em&gt;not&lt;/em&gt; initialized after the binding, but only &lt;em&gt;after&lt;/em&gt; a value was assigned to &lt;code&gt;$b&lt;/code&gt;.  This behaviour was specifically implemented this way to prevent accidental &lt;a href="https://docs.raku.org/language/subscripts#Autovivification" rel="noopener noreferrer"&gt;auto-vivification&lt;/a&gt;.  For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# False&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;               &lt;span class="c1"&gt;# {}&lt;/span&gt;
&lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;               &lt;span class="c1"&gt;# {a =&amp;gt; {b =&amp;gt; 42}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So even though &lt;code&gt;%h&amp;lt;a&lt;/code&gt;&amp;gt; is considered to be an &lt;code&gt;Associative&lt;/code&gt; because of the &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt;, the &lt;code&gt;:exists&lt;/code&gt; test will &lt;strong&gt;not&lt;/strong&gt; create a &lt;code&gt;Hash&lt;/code&gt; in &lt;code&gt;%h&amp;lt;a&amp;gt;&lt;/code&gt;.  Only &lt;em&gt;after&lt;/em&gt; a value has been assigned does &lt;code&gt;%h&amp;lt;a&amp;gt;&lt;/code&gt; and &lt;code&gt;%h&amp;lt;a&amp;gt;&amp;lt;b&amp;gt;&lt;/code&gt; actually spring to life.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy
&lt;/h2&gt;

&lt;p&gt;This rather lengthy introduction / diversion was to make you aware of some of the underlying mechanics of containers.  Because Raku supplies a full customizable class that allows you to create your own container logic: &lt;a href="https://docs.raku.org/type/Proxy" rel="noopener noreferrer"&gt;&lt;code&gt;Proxy&lt;/code&gt;&lt;/a&gt;.  And understanding what containers are about is helpful when working with that class.&lt;/p&gt;

&lt;p&gt;Creation of such a container is quite easy: all you need to supply are a &lt;code&gt;method&lt;/code&gt; for &lt;em&gt;fetching&lt;/em&gt; the value, and a &lt;code&gt;method&lt;/code&gt; for &lt;em&gt;storing&lt;/em&gt; a value (very similar to the pseudocode representation at the start of this blog post).  This is done with the named arguments &lt;code&gt;FETCH&lt;/code&gt; and &lt;code&gt;STORE&lt;/code&gt;.  Creation of a &lt;code&gt;Proxy&lt;/code&gt; object is usually done inside a subroutine for convenience.  A contrived example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;answer&lt;/span&gt; &lt;span class="nf"&gt;is&lt;/span&gt; &lt;span class="nf"&gt;rw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;Proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s"&gt;FETCH&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;$value&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="s"&gt;STORE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;storing &lt;/span&gt;&lt;span class="si"&gt;$new&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
          &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$new&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="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;# 42&lt;/span&gt;
&lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# storing 666&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;# 666&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The careful reader will have noticed that the &lt;code&gt;is rw&lt;/code&gt; attribute needs to be specified on the subroutine, otherwise the &lt;code&gt;Proxy&lt;/code&gt; would be de-containerized on return.  And that the result of calling the &lt;code&gt;answer&lt;/code&gt; subroutine was bound (&lt;code&gt;:=&lt;/code&gt;) instead of assigned, because assignment would also cause de-containerization and thus completely defeat the purpose of this exercise.&lt;/p&gt;

&lt;p&gt;Because the code in the supplied methods &lt;a href="https://docs.raku.org/syntax/closures" rel="noopener noreferrer"&gt;closes over&lt;/a&gt; the lexical variable &lt;code&gt;$value&lt;/code&gt;, that variable stays alive until the &lt;code&gt;Proxy&lt;/code&gt; object is destroyed.  So it offers an easy way to actually store the value for this &lt;code&gt;Proxy&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Inside the supplied methods you are completely free to put whatever code that you want.  As an example how that could work in a module, the &lt;a href="https://raku.land/zef:lizmat/Hash::MutableKeys" rel="noopener noreferrer"&gt;&lt;code&gt;Hash::MutableKeys&lt;/code&gt;&lt;/a&gt; distribution was created.  Another case of BDD (Blog Driven Development)!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You may have observed that the &lt;code&gt;Proxy&lt;/code&gt; object does not allow for a descriptor.  It was not considered to be needed, as you have all the flexibility you could possibly want.  If you want one in your &lt;code&gt;Proxy&lt;/code&gt; objects, you can create one yourself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This concludes the twelfth episode of cases of UPPER language elements in the Raku Programming Language, the fifth episode discussing interface methods.&lt;/p&gt;

&lt;p&gt;In this episode containers were described, as well as the special &lt;code&gt;Proxy&lt;/code&gt; class with its named arguments &lt;code&gt;STORE&lt;/code&gt; and &lt;code&gt;FETCH&lt;/code&gt;.  This &lt;code&gt;Proxy&lt;/code&gt; class provides a fully customizable container implementation.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

</content>
    <author>
      <name>Elizabeth Mattijsen</name>
    </author>
    <id>https://dev.to/lizmat/store-proxy-fetch-a07</id>
    <published>2026-02-20T11:39:50Z</published>
    <updated>2026-02-20T11:39:50Z</updated>
    <category term="rakulang"/>
    <category term="programming"/>
    <category term="tutorial"/>
  </entry>
  <entry>
    <title>Method Not Found Fallback</title>
    <link rel="alternate" href="https://dev.to/lizmat/method-not-found-fallback-5cn8" type="text/html"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;This is part eleven in the &lt;a href="https://dev.to/lizmat/series/35190"&gt;"Cases of UPPER"&lt;/a&gt; series of blog posts, describing the Raku syntax elements that are completely in UPPERCASE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This part will discuss the interface method that can be provided in a class to handle calls to methods that do not actually exist in this class (or its parents).&lt;/p&gt;

&lt;h2&gt;
  
  
  Some background
&lt;/h2&gt;

&lt;p&gt;Method dispatch in the &lt;a href="https://raku.org" rel="noopener noreferrer"&gt;Raku Programming Language&lt;/a&gt; is quite complicated, especially in the case of multi-dispatch.  But the first step is really to see if there is &lt;strong&gt;any&lt;/strong&gt; (multi) method with the given name.&lt;/p&gt;

&lt;p&gt;Internally this is handled by the &lt;a href="https://docs.raku.org/type/Metamodel/MROBasedMethodDispatch#method_find_method" rel="noopener noreferrer"&gt;&lt;code&gt;find_method&lt;/code&gt; method&lt;/a&gt; on the meta-object of the class (which is typically called with the &lt;a href="https://docs.raku.org/language/operators#methodop_%2E^" rel="noopener noreferrer"&gt;&lt;code&gt;.^method&lt;/code&gt; syntax&lt;/a&gt; on the class).&lt;/p&gt;

&lt;p&gt;So for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# an empty class&lt;/span&gt;
&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;dd&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;find_method&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;  &lt;span class="c1"&gt;# Mu&lt;/span&gt;
&lt;span class="nv"&gt;dd&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;find_method&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;gist&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;    &lt;span class="c1"&gt;# proto method gist (Mu $:: |) {*}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that an empty class &lt;code&gt;A&lt;/code&gt; (which by default inherits from the &lt;a href="https://docs.raku.org/type/Any" rel="noopener noreferrer"&gt;&lt;code&gt;Any&lt;/code&gt; class&lt;/a&gt;) does &lt;strong&gt;not&lt;/strong&gt; provide a method "foobar" (indicated by the &lt;a href="https://docs.raku.org/type/Mu" rel="noopener noreferrer"&gt;&lt;code&gt;Mu&lt;/code&gt; type object&lt;/a&gt;).  But it &lt;em&gt;does&lt;/em&gt; provide a &lt;code&gt;gist&lt;/code&gt; method (indicated by the &lt;code&gt;proto method gist (Mu $:: |) {*}&lt;/code&gt; representation of a &lt;a href="https://docs.raku.org/type/Callable" rel="noopener noreferrer"&gt;&lt;code&gt;Callable&lt;/code&gt;&lt;/a&gt;) because that is inherited from the &lt;code&gt;Any&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;It's this logic that is internally used by the dispatch logic to link a method name to an actual piece of code to be executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method not found
&lt;/h2&gt;

&lt;p&gt;If the dispatch logic can not find a method by the given name, then it will throw an &lt;a href="https://docs.raku.org/type/X/Method/NotFound" rel="noopener noreferrer"&gt;&lt;code&gt;X::Method::NotFound&lt;/code&gt;&lt;/a&gt; error.  One could of course use a &lt;a href="https://docs.raku.org/language/exceptions#Catching_exceptions" rel="noopener noreferrer"&gt;&lt;code&gt;CATCH&lt;/code&gt;&lt;/a&gt; phaser to handle such cases (as seen in &lt;a href="https://dev.to/lizmat/catch-control-i9o"&gt;part 6&lt;/a&gt; of this series).&lt;/p&gt;

&lt;p&gt;But there's a better and easier way to handle method names that could not be found.  That is, if you're interested in somehow making them less fatal.&lt;/p&gt;

&lt;h2&gt;
  
  
  FALLBACK
&lt;/h2&gt;

&lt;p&gt;If a class provides a &lt;a href="https://docs.raku.org/language/typesystem#Fallback_method" rel="noopener noreferrer"&gt;&lt;code&gt;FALLBACK&lt;/code&gt; method&lt;/a&gt; (either directly in its class, or by one of its base classes, or by ingestion of a role), then that method will be called whenever a method could &lt;em&gt;not&lt;/em&gt; be found.  The name of the method will be passed as the first argument, and all other arguments will be passed verbatim.&lt;/p&gt;

&lt;p&gt;A contrived example in which a non-existing method returns the &lt;em&gt;name&lt;/em&gt; of the method, but only if there were &lt;strong&gt;no&lt;/strong&gt; arguments passed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;FALLBACK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;# foo&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;# Too many positionals passed; expected 2 arguments but got 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So is there something special about the &lt;code&gt;FALLBACK&lt;/code&gt; method?   No, its only specialty is &lt;em&gt;when&lt;/em&gt; it is being called.  So you can make it a &lt;a href="https://docs.raku.org/syntax/multi-method" rel="noopener noreferrer"&gt;&lt;code&gt;multi&lt;/code&gt; method&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;multi&lt;/span&gt; &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;FALLBACK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;multi&lt;/span&gt; &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;FALLBACK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$value&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="si"&gt;$value&lt;/span&gt;&lt;span class="s2"&gt;.raku() passed to '&lt;/span&gt;&lt;span class="si"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;'&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="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;# foo&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;# 42 passed to 'bar'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other hand if you don't care about any arguments at all and just want to return &lt;a href="https://docs.raku.org/type/Nil" rel="noopener noreferrer"&gt;&lt;code&gt;Nil&lt;/code&gt;&lt;/a&gt;, you can specify the nameless capture &lt;code&gt;|&lt;/code&gt; as the signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;FALLBACK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;Nil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;# Nil&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;# Nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  An actual application
&lt;/h2&gt;

&lt;p&gt;The Raku Programming Language allows hyphens in identifier names (usually referred to as &lt;a href="https://en.wikipedia.org/wiki/Letter_case#Kebab_case" rel="noopener noreferrer"&gt;"kebab case"&lt;/a&gt;).  Many programmers coming from other programming languages are not really used to this: they are more comfortable with using underscores in identifiers (&lt;a href="https://en.wikipedia.org/wiki/Letter_case#Snake_case" rel="noopener noreferrer"&gt;"Snake case"&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Modern Raku programs usually use kebab case in identifiers.  So it's quite common for programmers to make the mistake of using an underscore where they should have been using a hyphen.  If such an error is made when writing a program, it will be a runtime error.  Which can be annoying.  In such a case, a &lt;code&gt;FALLBACK&lt;/code&gt; method can be a useful thing to have if it could correct such mistakes.&lt;/p&gt;

&lt;p&gt;This could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;E&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;bar&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="s2"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;FALLBACK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$corrected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;trans&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;find_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$corrected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;no_fallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;&amp;amp;code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;X::Method::&lt;/span&gt;&lt;span class="nv"&gt;NotFound&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;invocant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.^&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;throw&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "E" class has a method "foo-bar".  And a method "FALLBACK" that takes the name of the method that was not found (and putting any additional arguments in the &lt;a href="https://docs.raku.org/type/Capture" rel="noopener noreferrer"&gt;&lt;code&gt;Capture&lt;/code&gt;&lt;/a&gt; "c").&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the "c" is just an idiom for the name of a capture.  It could have any name, but "c" is nice and short.  If you want to use a name that's more clear to you, then please do so.  As long as you use the same name later on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It then converts all occurrences of underscore to hyphen in the name and then tries to find a &lt;code&gt;Callable&lt;/code&gt; for that name.  If that is successful it will execute the code with any arguments that were given by flattening the &lt;a href="https://docs.raku.org/language/signatures#Capture_parameters" rel="noopener noreferrer"&gt;&lt;code&gt;|c&lt;/code&gt; capture&lt;/a&gt;.  Otherwise it throws a "method not found" error.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;:no_fallback&lt;/code&gt; argument is needed to prevent the method lookup from producing the "FALLBACK" method if the method was not found.  Otherwise the code would loop forever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now this code will work instead of causing an execution error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;say E.foo-bar;  # foobar
say E.foo_bar;  # foobar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make this more generally usable this code could be put into a &lt;a href="https://docs.raku.org/language/objects#Parameterized_roles" rel="noopener noreferrer"&gt;&lt;code&gt;role&lt;/code&gt;&lt;/a&gt; and have that live as an installable module.  But that would be extra work, wouldn't it?&lt;/p&gt;

&lt;p&gt;Fortunately the writing of this blog post initiated the development of such a role (and associated distribution) called &lt;a href="https://raku.land/zef:lizmat/Method::Misspelt" rel="noopener noreferrer"&gt;&lt;code&gt;Method::Misspelt&lt;/code&gt;&lt;/a&gt;.  How's that for BDD (Blog Driven Development)?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the module introduces a few more features and optimizations, while handling keeping track of multiple classes ingesting the same role.  See the &lt;a href="https://github.com/lizmat/Method-Misspelt/blob/main/lib/Method/Misspelt.rakumod" rel="noopener noreferrer"&gt;internal documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This concludes the eleventh episode of cases of UPPER language elements in the Raku Programming Language, the fourth episode discussing interface methods.&lt;/p&gt;

&lt;p&gt;In this episode the &lt;code&gt;FALLBACK&lt;/code&gt; method was described, as well as some simple customizations.  And a &lt;a href="https://raku.land/zef:lizmat/Method::Misspelt" rel="noopener noreferrer"&gt;bonus module&lt;/a&gt; created for this blog post only.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

</content>
    <author>
      <name>Elizabeth Mattijsen</name>
    </author>
    <id>https://dev.to/lizmat/method-not-found-fallback-5cn8</id>
    <published>2026-02-17T15:22:31Z</published>
    <updated>2026-02-17T15:22:31Z</updated>
    <category term="rakulang"/>
    <category term="programming"/>
    <category term="tutorial"/>
  </entry>
  <entry>
    <title>Enumerating in RakuDoc v2</title>
    <link rel="alternate" href="https://dev.to/finanalyst/enumerating-in-rakudoc-v2-5d8j" type="text/html"/>
    <content type="html">&lt;p&gt;We needed a legal document with numbered &lt;em&gt;Articles&lt;/em&gt;, and the document needed to be in MarkDown for github issues, and in html, so naturally the source should be in RakuDoc.&lt;/p&gt;

&lt;p&gt;Although numbered headings and items were specified in RakuDoc v1 (aka POD6), they were never implemented. In RakuDoc v2 there was progress, and together with some tweaking of the &lt;em&gt;numitem&lt;/em&gt; templates, it was easy to write the RakuDoc source.&lt;/p&gt;

&lt;p&gt;However, when we were revising RakuDoc, Damian Conway had some extra ideas about generalising enumeration, including ideas about adding alias definitions so that the numbered block could be referenced later in the text.&lt;/p&gt;

&lt;p&gt;Since it had been so easy to tweak the &lt;em&gt;numitem&lt;/em&gt; templates, I thought it would be easy upgrade the specification of RakuDoc v2 to get these generalisations. Was I ever so wrong!!!! Ask a genius with decades of language design experience for a nice design and you get an effusion of ideas and extensions that make RakuDoc better than any editor I have ever used, but with a simplicity that makes it easy for a document author to understand.&lt;/p&gt;

&lt;p&gt;Another result of the redesign is to make the underlying specification of RakuDoc much clearer, something I will cover later.&lt;/p&gt;

&lt;p&gt;During the development process, my daughter mentioned that her friend had just finished a PhD dissertation and was complaining about how much time she needed to spend reformatting the text because the numbering kept getting out of sync. The problem with most editors is that most of the effort goes on perfecting the user-facing interface, while the underlying format is created &lt;em&gt;ad hoc&lt;/em&gt;, and enumeration is an addition. Getting the underlying structure right will make subsequent rendering easier. &lt;/p&gt;

&lt;p&gt;Just as the design was ending and the renderer passing most tests, I casually mentioned citations would be a good extension. The "standards" for citations number in the thousands! .oO(The &lt;a href="https://www.owleyes.org/text/jabberwocky/read/text-poem#root-22123-1" rel="noopener noreferrer"&gt;Jabberwocky&lt;/a&gt; ) But Damian &lt;em&gt;snicker-snacked&lt;/em&gt; his &lt;em&gt;vorpal blade&lt;/em&gt;, reducing the monstrous tangle to something easier to use. RakuDoc v2 now has a &lt;code&gt;=citation&lt;/code&gt; block and &lt;code&gt;Q&amp;lt;&amp;gt;&lt;/code&gt; markup to insert quoted citations. I will cover these additions in the next blog (as in: when I get the renderer to work with the new ideas).&lt;/p&gt;

&lt;p&gt;Back to enumerating RakuDoc, here are some examples to illustrate the new functionality.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Suppose you have a formula (or code or map or table or item in a list) and you want to number it, and then reference the number in the text? Then another formula gets added into the text before, well you would want the references to update as  well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suppose you have tables that you want to be enumerated separately from headings? But also by preference you want them to be enumerated in sequence with headings? That is the prefix to the table enumeration is the heading number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suppose you want Chinese, Roman, or Bengali numbering?&lt;br&gt;
AND suppose you also want the numbering to be a mix of numerals and other characters, such as brackets? This is a common requirement in legal documents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suppose you want Arbitrary words before after or in between the numbers? For example, &lt;em&gt;Article 1.&lt;/em&gt;, &lt;em&gt;Article 2.&lt;/em&gt; etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suppose you want to have the paragraphs numbered? Sometimes you might want the paragraphs numbered in sequence from the start of the document, and sometimes you want the numbering to restart after a new heading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suppose you want to have the Tables and the Formulae numbered in sequence? Or perhaps, for a section that explains some aspect of one formula, you want to number the formulae separately, but then return to the original sequence after that section?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The updated RakuDoc v2 allows for all of these possibilities, while also providing for sensible default option values.&lt;/p&gt;

&lt;p&gt;Moreover, RakuDoc allows for custom blocks, eg. LeafletMap - a map block that exposes the marvelous Leaflet library. Now it is an automatic part of the specification that prefixing a custom block with &lt;strong&gt;num&lt;/strong&gt; (numLeafletMap) will number the caption of the block.&lt;/p&gt;

&lt;p&gt;An HTML rendering of the new RakuDoc v2 specification containing the enumerated functionality can be found at &lt;a href="https://htmlpreview.github.io/?https://github.com/Raku/RakuDoc-GAMMA/blob/numalias-clarification/rakudoc_v2.html" rel="noopener noreferrer"&gt;RakuDoc enumeration branch&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the RakuDoc paradigms
&lt;/h2&gt;

&lt;p&gt;In the specification of RakuDoc, there are discussions about &lt;em&gt;directives&lt;/em&gt;, &lt;em&gt;blocks&lt;/em&gt;, &lt;em&gt;metaoptions&lt;/em&gt;, and a section on &lt;code&gt;=config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since the syntax for a &lt;em&gt;directive&lt;/em&gt; is &lt;strong&gt;almost&lt;/strong&gt; the same as the syntax of a &lt;em&gt;block&lt;/em&gt;, it is not immediately apparent what the difference is. As we developed the generic enumeration, it became much clearer what the difference is. &lt;/p&gt;

&lt;p&gt;Furthermore, the older specification covered multi-level headings and items. This functionality is now extended to all blocks, so &lt;code&gt;=numtable2&lt;/code&gt; or &lt;code&gt;=numcode3&lt;/code&gt; will be numbered in parts from the previous instance of &lt;code&gt;=table&lt;/code&gt; (the equivalent of &lt;code&gt;table1&lt;/code&gt;) or &lt;code&gt;=code&lt;/code&gt;. This means that we need to carefully distinguish between the &lt;strong&gt;block base&lt;/strong&gt; (eg., &lt;code&gt;table&lt;/code&gt; or &lt;code&gt;code&lt;/code&gt;), and the &lt;strong&gt;block level&lt;/strong&gt; (eg., 1, 2, 3). Together the &lt;em&gt;base&lt;/em&gt; and the &lt;em&gt;level&lt;/em&gt; create a &lt;strong&gt;blocktype&lt;/strong&gt;. These distinctions, although implied, were not so clear in the older specification.&lt;/p&gt;

&lt;p&gt;Let's return to the &lt;code&gt;=config&lt;/code&gt; directive. The first parameter of &lt;code&gt;=config&lt;/code&gt; is the name of a &lt;em&gt;blocktype&lt;/em&gt;. Note that the &lt;code&gt;num&lt;/code&gt; prefix is not a part of the &lt;em&gt;blocktype&lt;/em&gt; and only indicates that the enumeration associated with the instance needs to be rendered. Consequently, the presence or absence of 'num' in the config parameter has no significance. The next &lt;code&gt;=config&lt;/code&gt; parameters are all, and may only be, metadata options. &lt;/p&gt;

&lt;p&gt;The function of the &lt;code&gt;=config&lt;/code&gt; directive is to &lt;em&gt;distribute&lt;/em&gt; the named metadata options, and their values, to the named blocktype. In addition, the same metadata option can be specified on a blocktype instance (using either the &lt;code&gt;=for&lt;/code&gt; or &lt;code&gt;=begin&lt;/code&gt; directives), in which case it takes precedence over the option in the config. A consequence of this paradigm is that each metadata option has to have a semantic significance in the context of a blocktype instance.&lt;/p&gt;

&lt;p&gt;One of the design aims was to give a document author the choice of restarting the enumeration for some blocktype when another blocktype is encountered. For example, the original specfication for &lt;code&gt;=numitem&lt;/code&gt; included the idea that whenever a sequence of &lt;code&gt;=numitem&lt;/code&gt;s was encountered, they would form an ordered set, and that if another block, such as a paragraph, was encountered, the enumeration would be restarted.&lt;/p&gt;

&lt;p&gt;This means that the occurrence of a &lt;code&gt;=head&lt;/code&gt; restarts the &lt;code&gt;item&lt;/code&gt; counter. This cannot be controlled within the handler of a block. Consequently, any option affecting block counting needs to be distinct from the rendering of the blocks themselves. &lt;/p&gt;

&lt;p&gt;After some design iterations, a new &lt;em&gt;directive&lt;/em&gt; called &lt;code&gt;=counter&lt;/code&gt; was introduced. A directive, as opposed to a block, affects all subsequent blocks in the RakuDoc source, within the same scope. A block, and the metadata options operating on the blocktype, only affects its immediate contents.&lt;/p&gt;

&lt;p&gt;Further, it became clear that a block and its counter were different objects, although for simplicity they have the same name. For most needs, an author does not need to know that a counter and a block are different, except that when a new counter is needed, the difference becomes necessary. In a similar way, for many purposes it doesn't matter whether a number is an integer or a string, except when it does. Raku allows for things to become complicated when the author needs it to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to experiment with enumerations?
&lt;/h2&gt;

&lt;p&gt;To make it easier to experiment with RakuDoc and the enumerated functionality, I have developed a Docker image called &lt;code&gt;browser-editor&lt;/code&gt;. It is based on an Alpine image and contains &lt;em&gt;raku&lt;/em&gt;, &lt;em&gt;Cro&lt;/em&gt;, and the latest version of &lt;code&gt;Rakuast::RakuDoc::Render&lt;/code&gt; (currently not yet in the fez system).&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;podman&lt;/code&gt;, the image can be put into a container and run locally on Linux based systems, thus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;podman pull docker.io/finanalyst/browser-editor:latest
podman run -d -v .:/browser/publication --rm -name rb docker.io/finanalyst/browser-editor:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Mac silicon, a small change is needed to indicate the platform inside the docker image is based on Linux, thus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;podman run -d -v .:/browser/publication --rm --platform linux/amd64 --name rb docker.io/finanalyst/browser-editor:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases the container is given the arbitrary name &lt;code&gt;rb&lt;/code&gt;, and so when it is time to stop the container, the following is sufficient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;podman stop rb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The directory that the container is started from will then linked to the container's &lt;code&gt;/browser/publication&lt;/code&gt; directory, and changes and new RakuDoc source files will be saved in that directory.&lt;/p&gt;

&lt;p&gt;A RakuDoc source can then be edited and the HTML rendering is created on the fly, by pointing a browser at (setting the browser URL to) &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You should see something like the following in the browser:&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%2Fk3x5jvweu1l0awig8sww.png" 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%2Fk3x5jvweu1l0awig8sww.png" alt=" " width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two frameworks exist: one needing no internet connection - a minimal single file rendering, and another that uses plugins to expose some useful third-party libraries and the more sophisticated Bulma CSS framework. The choice is toggled using the 'online' button.&lt;/p&gt;

&lt;p&gt;Try selecting 'online' and copying in the following test source by Damian Conway to see some different effects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=begin rakudoc
=TITLE Taster source
=numitem One
=numitem Two
=counter item :restart(42)
=numitem Three
=counter item :restart
=numitem Four
=counter item :prefix&amp;lt;head3&amp;gt;
=numitem Five
=counter item :!restart
=para ???
=numitem Six

=numpara
S&amp;lt;Now is the winter of our "no content"
Made glorious summer by Camelia’s bloom;
And all backlog that lour’d upon our docs
In deep commits is buried, link’d, and tagged.
Our nightly builds now wear triumphant green,
Our failing tests to passing smiles are turn’d;
Grim sighs of “ere next Yule” have chang’d to grins,
And hacker dread to blog posts boldly strung.&amp;gt;

=numpara
S&amp;lt;But I—long nurs’d on RFCs and hope,
Deform’d by specs that shifted as I read,
Unfit for idle scripts or stable sleep—
Am set, since long delays are now no more,
To ship Raku...and break the world anew.&amp;gt;

=numcode
$x = any &amp;lt;1 2 3&amp;gt;;

=for numcode :caption&amp;lt;Same thing, just labelled&amp;gt;
$x = any &amp;lt;1 2 3&amp;gt;;


=for numformula :caption&amp;lt;This means nothing!&amp;gt;
x^2 = y_j + \sum z_i

=for numformula :caption&amp;lt;This means nothing!&amp;gt; :alt&amp;lt; xH&amp;lt;2&amp;gt; = yJ&amp;lt;1&amp;gt; + E&amp;lt;GREEK CAPITAL LETTER SIGMA&amp;gt; zJ&amp;lt;i&amp;gt; &amp;gt;
x^2 = y_j + \sum z_i

=for numformula :alt&amp;lt; (1+x)H&amp;lt;n&amp;gt; = E&amp;lt;GREEK CAPITAL LETTER SIGMA&amp;gt; H&amp;lt;n&amp;gt;CJ&amp;lt;i&amp;gt; xH&amp;lt;i&amp;gt; &amp;gt; :caption&amp;lt;This is actually right&amp;gt;
(1+x)^n = \sum_{i=0}^n {n \choose i} x^i

=for numinput
Hey type something:

=numoutput
You typed: hsdkhldkhskdhasd

=counter numtable :restart(33456)
=begin numtable :caption&amp;lt;Encryption table&amp;gt; :form&amp;lt;Example %R: %C:pc&amp;gt;
=row
=cell A
=cell B
=cell C
=row
=cell D
=cell E
=cell F
=end numtable

=end rakudoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should look like the following (or at least the top part).&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%2Fjz5as2qt1ds7w6hlqmep.png" 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%2Fjz5as2qt1ds7w6hlqmep.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example shows some features like numbering paragraphs, code examples and tables. But you will also see the difference between the two rendering contexts. The online version has access to an online latex rendering resource, so the formula are nicely rendered, whilst the off-line version only renders to the raw formula or a character-based alternative - if provided.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding the examples in the introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Adding an alias to a block
&lt;/h3&gt;

&lt;p&gt;Suppose we want to enumerate a code sample and then refer to it later, we can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=begin rakudoc :!toc
=TITLE Enumerations
=for numcode :numalias&amp;lt;SAY_EX&amp;gt; :lang&amp;lt;raku&amp;gt;
my %h = &amp;lt;one two three&amp;gt; Z=&amp;gt; ^3;
say %h;

=numoutput {one =&amp;gt; 0, three =&amp;gt; 2, two =&amp;gt; 1}

=for numcode :numalias&amp;lt;PUT_EX&amp;gt; :lang&amp;lt;raku&amp;gt;
my %h = &amp;lt;one two three&amp;gt; Z=&amp;gt; ^3;
put %h;

=for numoutput                                                                                                                                    
one     0
three   2
two     1

The difference between A&amp;lt;SAY_EX&amp;gt; and A&amp;lt;PUT_EX&amp;gt; is that C&amp;lt;say&amp;gt; and C&amp;lt;put&amp;gt; use different methods to convert the C&amp;lt;%h&amp;gt; structure into printable strings.
=end rakudoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the browser-editor image, we will get an HTML rendering something like:&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%2Fk0txyosqpbehs2loi324.png" 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%2Fk0txyosqpbehs2loi324.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;=begin rakudoc :!toc&lt;/code&gt; and &lt;code&gt;=end rakudoc&lt;/code&gt; are used to &lt;em&gt;top and tail&lt;/em&gt; the RakuDoc example above because the HTML renderer expects a complete Raku program, and a RakuDoc source (currently) needs the RakuDoc to be within a &lt;code&gt;=rakudoc&lt;/code&gt; block. The &lt;code&gt;:!toc&lt;/code&gt; switches off the automatic Table of Contents that the HTML utility of the &lt;code&gt;Rakuast::RakuDoc::Render&lt;/code&gt; distribution generates. (Try removing &lt;code&gt;:!toc&lt;/code&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prefixing an enumeration with another counter
&lt;/h3&gt;

&lt;p&gt;Suppose we want out tables to have enumerations that align with the enumerations of the headings. So this means we are requiring a different sort of behaviour from the counter associated with the &lt;em&gt;table&lt;/em&gt; block base. Consequently, we need to use the &lt;code&gt;=counter&lt;/code&gt; directive. Also note that we are prefixing with the &lt;code&gt;head2&lt;/code&gt; block, which has an implicit prefix of &lt;code&gt;head1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=begin rakudoc :!toc
=TITLE Prefixes
=counter table :prefix&amp;lt;head&amp;gt;
=numhead First title
=numhead2 Sub first title
=for numtable :caption&amp;lt;First table&amp;gt;
| one | two |
=for numtable :caption&amp;lt;Second table&amp;gt;
| three | four |
=numhead Second Title
=counter table :restart(6)
=for numtable :caption&amp;lt;Third table&amp;gt;
| five | six | seven | eight |
=for numtable2 :caption&amp;lt;Subordinate table&amp;gt;
| nine | ten |
| nine | ten |
=end rakudoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A table must have some content, and the 'visual' table format is the minimum possible&lt;/li&gt;
&lt;li&gt;In order to make the prefix numbering a bit clearer, I manually restarted the &lt;code&gt;table&lt;/code&gt; counter to &lt;code&gt;6&lt;/code&gt; before &lt;em&gt;Third table&lt;/em&gt;. &lt;/li&gt;
&lt;/ul&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%2Fm3sj41l703ospwnwfq3u.png" 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%2Fm3sj41l703ospwnwfq3u.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Enumerations with different numbering systems
&lt;/h3&gt;

&lt;p&gt;To illustrate the multi-lingual ability of RakuDoc (and Raku in general), lets use Chinese, Roman and Bengali for multilevel headings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=begin rakudoc :!toc
=TITLE Some non-Arabic numerals
=config head :form&amp;lt; %Z %D &amp;gt;
=config head2 :form&amp;lt; ｢%Z｣%R %D &amp;gt;
=config head3 :form&amp;lt; ｢%Z｣%R｢%B｣ %D &amp;gt;
=numhead First title
=numhead Second title
=numhead3 Sub-sub-head one (implies the sub-head)
=numhead3 Sub-sub-head two
=numhead2 Sub-head first explicit
=numhead2 Sub-head second explicit
=for numformula2 :form&amp;lt;%T %Z.%R. &amp;gt;
\begin{align*}
\sum_{i=1}^{k+1} i^{3}
&amp;amp;= \biggl(\sum_{i=1}^{n} i^{3}\biggr) +  i^3\\
&amp;amp;= \frac{k^{2}(k+1)^{2}}{4} + (k+1)^3 \\
\end{align*}
=end rakudoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce an HTML rendering a bit like&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%2F74qul9kyvvuv3ar92cyl.png" 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%2F74qul9kyvvuv3ar92cyl.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Including arbitrary text
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;:numform&lt;/code&gt; option is very flexible and in fact the brackets in the previous example are arbitrary text. The following RakuDoc source&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=begin rakudoc :!toc
=TITLE Arbitrary text in enumeration
=config head :form&amp;lt; Article %N. %D &amp;gt;
=config head2 :form&amp;lt; Article %N.%r. %D &amp;gt;
=config head3 :form&amp;lt; Article %N.%r｢%Z｣ %D &amp;gt;
=numhead First title
=numhead Second title
=numhead3 Sub-sub-head one (implies the sub-head)
=numhead3 Sub-sub-head two
=numhead2 Sub-head first explicit
=numhead2 Sub-head second explicit
=end rakudoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will produce something like:&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%2Fe170xc86qal4m176m1cz.png" 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%2Fe170xc86qal4m176m1cz.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Numbering paragraphs
&lt;/h3&gt;

&lt;p&gt;In RakuDoc, paragraphs as in all text editors, are strings of text ending in a blank line or a new block (for RakuDoc). There is no need to mark a paragraph block, but it will be equivalent to a block marked &lt;code&gt;=para&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;By default, each paragraph is numbered from the start of the document. In order to see the enumeration, the paragraph does need to be started with a &lt;code&gt;=numpara&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this example, we want to number paragraphs in each section marked with a heading. So we need to tell the counter which conditions it is restarted by; in this case after every &lt;code&gt;=head&lt;/code&gt; (by default a bare block name has a level of 1). There are both &lt;code&gt;:restart-after&lt;/code&gt; and &lt;code&gt;:restart-except-after&lt;/code&gt; conditions, but that's all we'll say about them here.&lt;/p&gt;

&lt;p&gt;The RakuDoc source is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=begin rakudoc :!toc
=TITLE Restarting after headings
=counter para :restart-after&amp;lt;head&amp;gt;
=head First heading
=numpara First line
=numpara Second line
=numpara Third line
=head Second heading
=numpara First line 2
=numpara Second line 2
=head2 Subordinate heading does not restart the paragraphs
=numpara Third line 2
=numpara Fourth para
=end rakudoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The source will yield something like:&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%2Fex646enjfrotdchyiphj.png" 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%2Fex646enjfrotdchyiphj.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom counters and block scopes
&lt;/h3&gt;

&lt;p&gt;We want to number code and formulae using the same counter, but also we want to explain some formula with a special numbering that is then &lt;em&gt;forgotten&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Since all &lt;code&gt;=config&lt;/code&gt; and &lt;code&gt;=counter&lt;/code&gt; statements are scoped, all we need to do to get the special numbering is to create a &lt;code&gt;=section&lt;/code&gt;, which introduces a new block scope. The previous config/counter options continue, unless explicitly overridden.&lt;/p&gt;

&lt;p&gt;However, it would not be useful if upon exiting a section, the numbering of a counter reverts to the value before the section. So there is a subtle distinction between the &lt;em&gt;counter&lt;/em&gt; and the value of the count it contains. The &lt;em&gt;counter&lt;/em&gt; options, such as its prefix, and when it is restarted, are scoped, but the value of the counter is not scoped. In order to reset the counter value, the counter has to be reset.&lt;/p&gt;

&lt;p&gt;RakuDoc v2 clarified the idea of custom blocks. Previously it was implied that developers could have their own blocks, but in V.2 the difference between &lt;em&gt;built in&lt;/em&gt; and &lt;em&gt;custom&lt;/em&gt; blocks was clarified: custom blocks must contain a mix of upper and lower case letters (more precisely characters with the Unicode properties &lt;em&gt;Lu&lt;/em&gt; and &lt;em&gt;Ll&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;The enumeration options use this idea by creating custom counters. Since this is something that managed by a block, the &lt;code&gt;:counter&lt;/code&gt; option is provided to the appropriate blocks using a &lt;code&gt;=config&lt;/code&gt; directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=begin rakudoc :!toc
=TITLE Using custom counnters
=config formula :counter&amp;lt; FormulaeTables &amp;gt;
=config table :counter&amp;lt; FormulaeTables &amp;gt;
=numhead First title
=numtable 
| one | two | three |
=numtable
| more | tabula data |
| 5 | 6 |
| 7 | 8 |
=numformula E = mc^2
=numformula e^{\pi i} = -1

=begin section
=config table :counter&amp;lt; Derivation &amp;gt; :form&amp;lt;Aside: %T %N&amp;gt;

=numhead2 Some explanation
=numtable
| this | data | is | more | detailed |
| 1 | 2 | 3 | 4 | 5 |
=end section

=numhead Continuing
=numtable
| here | we | resume |
=end rakudoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce something like&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%2Filgn2tm7d2yar3ta8dkm.png" 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%2Filgn2tm7d2yar3ta8dkm.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Afterword
&lt;/h2&gt;

&lt;p&gt;We have only just completed the revised specification, and the Renderer has only just been developed. It is inevitable that there will be flaws, and the styling choices may not be liked by everyone. &lt;/p&gt;

&lt;p&gt;Even so, we think this new upgrade of RakuDoc v2 will prove to have a much wider applicability than just a documentation aid to Raku programs.&lt;/p&gt;

&lt;p&gt;The docker image allows anyone to experiment with the new RakuDoc functionality immediately without needing to install the whole Raku / Cro / Rakuast::RakuDoc::Render stack and some dependencies, such as Dart Sass, locally.&lt;/p&gt;

</content>
    <author>
      <name>Richard Hainsworth</name>
    </author>
    <id>https://dev.to/finanalyst/enumerating-in-rakudoc-v2-5d8j</id>
    <published>2026-02-15T11:31:14Z</published>
    <updated>2026-02-15T11:31:14Z</updated>
    <category term="rakulang"/>
    <category term="rakudoc"/>
  </entry>
  <entry>
    <title>Dead Simple CI Introduction</title>
    <link rel="alternate" href="https://dev.to/melezhik/dead-simple-ci-introduction-1jh6" type="text/html"/>
    <content type="html">&lt;p&gt;&lt;a href="http://deadsimpleci.sparrowhub.io/doc/README" rel="noopener noreferrer"&gt;Dsci&lt;/a&gt; is a brand new kid on the cicd area. It allows use of general programming languages to create ci scenarios.&lt;/p&gt;

&lt;p&gt;——-&lt;/p&gt;

&lt;p&gt;Consider some imaginary case of building and deploying an application as docker container. So, logically we have two main stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;build docker image from source code &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;deploy docker image using docker pull and docker run commands&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see how dsci could tackle such a scenario …&lt;/p&gt;

&lt;p&gt;——-&lt;/p&gt;

&lt;h1&gt;
  
  
  Pipeline file
&lt;/h1&gt;

&lt;p&gt;The main concept we start with is so called ‘pipeline file’.&lt;/p&gt;

&lt;p&gt;It’s just yaml file containing a list of jobs to be performed. Every job is executed on isolated docker container, execution logic is always sequential - one job, by another.&lt;/p&gt;

&lt;p&gt;This pattern yet simple however covers the majority of use cases:&lt;/p&gt;

&lt;p&gt;jobs.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy/&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus, every element of job list is a job, where job has some unique identifier and path to location of job file.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conditional job logic
&lt;/h1&gt;

&lt;p&gt;Usually there are some conditions when and what ci scripts are triggered. Those conditions may be based on different criteria, but usually they depend on branch names.&lt;/p&gt;

&lt;p&gt;Dsci utilizes a special syntax to define those rules. Let’s say we only want to deploy if source branch is main, and perform build for all branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy/&lt;/span&gt; 
     &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&amp;lt;ref&amp;gt; eq "refs/heads/main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read more on job conditions on dsci documentation - &lt;a href="https://github.com/melezhik/DSCI/blob/main/job-cond.md" rel="noopener noreferrer"&gt;https://github.com/melezhik/DSCI/blob/main/job-cond.md&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Passing parameters to job
&lt;/h1&gt;

&lt;p&gt;To pass parameters to job, just use &lt;code&gt;params:&lt;/code&gt; key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/&lt;/span&gt;
     &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
       &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.1.0&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy/&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those parameters could be thought as overrides for default ones, however dsci allows more then that - pass results ( states ) from one job to another, see later.&lt;/p&gt;

&lt;h1&gt;
  
  
  Job file
&lt;/h1&gt;

&lt;p&gt;The next important building block of the hierarchy is so called “job file” defining main job logic.&lt;/p&gt;

&lt;p&gt;Job file needs to be named depending on language of choice, in our example we use Bash as it usually is enough for many use cases. But using other languages is also possible. If one needs more flexibility they may chose Python or Golang&lt;/p&gt;

&lt;p&gt;build/task.bash&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="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;config version&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;tag_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;.&lt;span class="nv"&gt;$version&lt;/span&gt;
docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; app:&lt;span class="nv"&gt;$tag_version&lt;/span&gt;
docker push repo/app:&lt;span class="nv"&gt;$tag_version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this simple example our job file is just a single task job. However if there is a need to split complex job into several tasks they may do so by using job.$ext file approach. This file needs to be named according language of choice. &lt;/p&gt;

&lt;p&gt;Let’s say we have three tasks - configure, build and test - incorporated into build job, we may run them one by one like this:&lt;/p&gt;

&lt;p&gt;build/job.py&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="c1"&gt;#!/bin/python
&lt;/span&gt;&lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we put those tasks under build/tasks/ directory like this:&lt;/p&gt;

&lt;p&gt;build/tasks/configure/task.bash&lt;br&gt;
build/tasks/build/tasks.bash&lt;br&gt;
build/tasks/tests/task.bash&lt;/p&gt;

&lt;p&gt;In this case we have modular setup of our ci job.  &lt;/p&gt;

&lt;p&gt;The neat thing about this DSL, dsci provides the same SDK for all supported programming languages.&lt;/p&gt;

&lt;p&gt;Read more about jobs and tasks on dsci documentation web site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://deadsimpleci.sparrowhub.io/doc/task" rel="noopener noreferrer"&gt;http://deadsimpleci.sparrowhub.io/doc/task&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://deadsimpleci.sparrowhub.io/doc/job" rel="noopener noreferrer"&gt;http://deadsimpleci.sparrowhub.io/doc/job&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Passing results between jobs
&lt;/h1&gt;

&lt;p&gt;Let’s make our last job example more realistic and return docker image tag dynamically created by build job back to deploy job. We may want to do so deploy jobs know what tag to pull before deploy. All we need is to add extra line to save the job state into internal dsci cache:&lt;/p&gt;

&lt;p&gt;build/task.bash&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="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;config version&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;tag_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;.&lt;span class="nv"&gt;$version&lt;/span&gt;
docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; app:&lt;span class="nv"&gt;$tag_version&lt;/span&gt;
docker push repo/app:&lt;span class="nv"&gt;$tag_version&lt;/span&gt;
update_state tag &lt;span class="nv"&gt;$tag_version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;update_state() is very handy function allowing to pass states between different tasks and jobs. It’s implemented for all supported languages.&lt;/p&gt;

&lt;p&gt;To pick up tag name in deploy job we can use already mentioned config() function:&lt;/p&gt;

&lt;p&gt;deploy/task.bash&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="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;span class="nv"&gt;tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;config tag&lt;span class="si"&gt;)&lt;/span&gt;
docker pull repo/app@&lt;span class="nv"&gt;$tag&lt;/span&gt;
docker stop &lt;span class="nt"&gt;-t&lt;/span&gt; 1 container &lt;span class="o"&gt;||&lt;/span&gt; :
docker run &lt;span class="nt"&gt;-rm&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; container &lt;span class="nt"&gt;-td&lt;/span&gt; repo/app@&lt;span class="nv"&gt;$tag&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read more about job and tasks states on dsci documentation ( the links above ^^ )&lt;/p&gt;

&lt;h1&gt;
  
  
  Secrets
&lt;/h1&gt;

&lt;p&gt;Let’s modify build job example with pushing image to docker registry. To do a push we need to authenticate against a docker registry first. Dsci enables simple way to pass secrets to pipelines.&lt;/p&gt;

&lt;p&gt;This time let’s rewrite our job file on Python for convenience:&lt;/p&gt;

&lt;p&gt;build/job.py&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="c1"&gt;#!/bin/python
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="n"&gt;password&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then modify build task to handle password parameter:&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="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;config version&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;tag_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;.&lt;span class="nv"&gt;$version&lt;/span&gt;
docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; app:&lt;span class="nv"&gt;$tag_version&lt;/span&gt;
update_state tag &lt;span class="nv"&gt;$tag_version&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$password&lt;/span&gt; | docker login &lt;span class="nt"&gt;--username&lt;/span&gt; your-username &lt;span class="nt"&gt;--password-stdin&lt;/span&gt;

docker push repo/app:&lt;span class="nv"&gt;$tag_version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see secrets passed into pipelines as environment variables.&lt;/p&gt;

&lt;p&gt;And unlike other task and jobs parameters they never saved in job reports or cache files.  &lt;/p&gt;

&lt;p&gt;—-&lt;/p&gt;

&lt;h1&gt;
  
  
  Deployment on localhost
&lt;/h1&gt;

&lt;p&gt;By default dsci pipelines run inside some docker container, this fits situation when one needs run purely ci code - for example build and run some unit tests. CD part comes to play when build artifacts are ready for deploy. &lt;/p&gt;

&lt;p&gt;Dsci allows switch to deployment environment by using &lt;code&gt;localhost&lt;/code&gt; switcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/&lt;/span&gt;
     &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bar&lt;/span&gt;
       &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.1.0&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt;
     &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
     &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy/&lt;/span&gt;
     &lt;span class="na"&gt;localhost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that case deployment occurs on VM running dsci orchestrator and which allows to restart docker container with new image version right on VM&lt;/p&gt;

&lt;p&gt;——-&lt;/p&gt;

&lt;p&gt;That is it. &lt;/p&gt;

&lt;p&gt;This simple but real life example shows how easy and one can write cicd pipelines using dsci framework and how flexible it is.&lt;/p&gt;

&lt;p&gt;Hopefully you like it. &lt;/p&gt;

&lt;p&gt;—-&lt;/p&gt;

&lt;p&gt;For comprehensive documentation and more information please visit dsci web site - &lt;a href="http://deadsimpleci.sparrowhub.io/doc/README" rel="noopener noreferrer"&gt;http://deadsimpleci.sparrowhub.io/doc/README&lt;/a&gt;&lt;/p&gt;

</content>
    <author>
      <name>Alexey Melezhik</name>
    </author>
    <id>https://dev.to/melezhik/dead-simple-ci-introduction-1jh6</id>
    <published>2026-02-14T13:11:55Z</published>
    <updated>2026-02-14T13:11:55Z</updated>
    <category term="cicd"/>
    <category term="pipelines"/>
    <category term="forgejo"/>
  </entry>
  <entry>
    <title>Associative Methods</title>
    <link rel="alternate" href="https://dev.to/lizmat/associative-methods-2mcl" type="text/html"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;This is part ten in the &lt;a href="https://dev.to/lizmat/series/35190"&gt;"Cases of UPPER"&lt;/a&gt; series of blog posts, describing the Raku syntax elements that are completely in UPPERCASE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This part will discuss the interface methods that one can implement to provide a custom &lt;a href="https://docs.raku.org/type/Associative" rel="noopener noreferrer"&gt;&lt;code&gt;Associative&lt;/code&gt;&lt;/a&gt; interface in the &lt;a href="https://raku.org" rel="noopener noreferrer"&gt;Raku Programming Language&lt;/a&gt;.  Associative access is indicated by the &lt;a href="https://docs.raku.org/language/operators#postcircumfix_{_}" rel="noopener noreferrer"&gt;postcircumfix { } operator&lt;/a&gt; (aka the "hash indexing operator").&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a way this blog post is a &lt;a href="https://en.wikipedia.org/wiki/Fish_Licence" rel="noopener noreferrer"&gt;cat license&lt;/a&gt; ("a dog licence with the word 'dog' crossed out and 'cat' written in crayon") from the &lt;a href="https://dev.to/lizmat/positional-methods-439i"&gt;previous post&lt;/a&gt;.  But there are some subtle differences between the &lt;code&gt;Positional&lt;/code&gt; and the &lt;code&gt;Associative&lt;/code&gt; roles, so just changing all occurrences of "POS" in "KEY" will not cut it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Some background
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Associative&lt;/code&gt; role is really just a marker, just as the &lt;code&gt;Positional&lt;/code&gt; role.  It does &lt;strong&gt;not&lt;/strong&gt; enforce any methods to be provided by the consuming class.  So why use it?  Because it is &lt;em&gt;that&lt;/em&gt; constraint that is being checked for any variable with a &lt;code&gt;%&lt;/code&gt; &lt;a href="https://docs.raku.org/language/glossary#Sigil" rel="noopener noreferrer"&gt;sigil&lt;/a&gt;.  An example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;Foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will show an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type check failed in binding; expected Associative but got Foo (Foo)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if we make that class ingest the &lt;code&gt;Associative&lt;/code&gt; marker role, it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nv"&gt;Foo&lt;/span&gt; &lt;span class="nv"&gt;does&lt;/span&gt; &lt;span class="nv"&gt;Associative&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# (Any)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and it is even possible to call the postcircumfix &lt;code&gt;{ }&lt;/code&gt; operator on it!  Although it doesn't return anything really useful.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the binding operator &lt;code&gt;:=&lt;/code&gt; was used: otherwise it would be interpreted as initializing a hash &lt;code&gt;%h&lt;/code&gt; with a single value, which would complain with an "Odd number of elements found where hash initializer expected: Only saw: type object 'Foo'" execution error.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Postcircumfix { }
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;postcircumfix { }&lt;/code&gt; operator performs all of the work of slicing and dicing objects that perform the &lt;code&gt;Associative&lt;/code&gt; role, and handling all of the adverbs: &lt;code&gt;:exists&lt;/code&gt;, &lt;code&gt;:delete&lt;/code&gt;, &lt;code&gt;:p&lt;/code&gt;, &lt;code&gt;:kv&lt;/code&gt;, &lt;code&gt;:k&lt;/code&gt;, and &lt;code&gt;:v&lt;/code&gt;.  But it is completely agnostic about how this is actually done, because all it does is calling the interface methods that are (implicitely) provided by the object, just as with the &lt;code&gt;Positional&lt;/code&gt; role.  Except the names of the interface methods are different.  For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is actually doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;AT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;under the hood.  So these interface methods are the ones that actually know how to work on an &lt;a href="https://docs.raku.org/type/Hash" rel="noopener noreferrer"&gt;&lt;code&gt;Hash&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.raku.org/type/Map" rel="noopener noreferrer"&gt;&lt;code&gt;Map&lt;/code&gt;&lt;/a&gt; or a &lt;a href="https://docs.raku.org/type/PseudoStash" rel="noopener noreferrer"&gt;&lt;code&gt;PseudoStash&lt;/code&gt;&lt;/a&gt;, or any other class that does the &lt;code&gt;Associative&lt;/code&gt; role.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Interface Methods
&lt;/h2&gt;

&lt;p&gt;Let's introduce the cast of &lt;em&gt;this&lt;/em&gt; show (the interface methods associated with the &lt;code&gt;Associative&lt;/code&gt; role):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.raku.org/language/subscripts#method_AT-KEY" rel="noopener noreferrer"&gt;&lt;code&gt;AT-KEY&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.raku.org/language/subscripts#method_EXISTS-KEY" rel="noopener noreferrer"&gt;&lt;code&gt;EXISTS-KEY&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.raku.org/language/subscripts#method_DELETE-KEY" rel="noopener noreferrer"&gt;&lt;code&gt;DELETE-KEY&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.raku.org/language/subscripts#method_ASSIGN-KEY" rel="noopener noreferrer"&gt;&lt;code&gt;ASSIGN-KEY&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.raku.org/language/subscripts#method_BIND-KEY" rel="noopener noreferrer"&gt;&lt;code&gt;BIND-KEY&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.raku.org/type/Associative#method_STORE" rel="noopener noreferrer"&gt;&lt;code&gt;STORE&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.raku.org/type/Map#method_keys" rel="noopener noreferrer"&gt;&lt;code&gt;keys&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AT-KEY
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;AT-KEY&lt;/code&gt; method is the most important method of the interface methods of the &lt;code&gt;Associative&lt;/code&gt; role: it is expected to take the argument as a key, and return the value associated with that key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the key does &lt;strong&gt;not&lt;/strong&gt; need to be a string, it could be any object.  It's just that the implenentation of &lt;code&gt;Hash&lt;/code&gt; and &lt;code&gt;Map&lt;/code&gt; will coerce the key to a string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;AT-KEY&lt;/code&gt; method should return a container if that is appropriate, which is usually the case.  Which means you probably should specify &lt;a href="https://docs.raku.org/routine/is%20raw" rel="noopener noreferrer"&gt;&lt;code&gt;is raw&lt;/code&gt;&lt;/a&gt; on the &lt;code&gt;AT-KEY&lt;/code&gt; method if you're implementing that yourself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# same as %h.AT-KEY("bar")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  EXISTS-KEY
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;EXISTS-KEY&lt;/code&gt; method is expected to take the argument as a key, and return a &lt;a href="https://docs.raku.org/type/Bool" rel="noopener noreferrer"&gt;&lt;code&gt;Bool&lt;/code&gt;&lt;/a&gt; value indicating whether that key is considered to be existing or not.  This is what is being called when the &lt;a href="https://docs.raku.org/type/Hash#:exists" rel="noopener noreferrer"&gt;&lt;code&gt;:exists&lt;/code&gt;&lt;/a&gt; adverb is specified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# same as %h.EXISTS-KEY("bar")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  DELETE-KEY
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;DELETE-KEY&lt;/code&gt; method is supposed to act very much like the &lt;code&gt;AT-KEY&lt;/code&gt; method.  But it is also expected to remove the key so that the &lt;code&gt;EXISTS-KEY&lt;/code&gt; method will return &lt;code&gt;False&lt;/code&gt; for that key in the future.  This is what is being called when the &lt;a href="https://docs.raku.org/type/Hash#:delete" rel="noopener noreferrer"&gt;&lt;code&gt;:delete&lt;/code&gt;&lt;/a&gt; adverb is specified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# same as %h.DELETE-KEY("bar")&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ASSIGN-KEY
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;ASSIGN-KEY&lt;/code&gt; method is a convenience method that &lt;em&gt;may&lt;/em&gt; be called when assigning (&lt;code&gt;=&lt;/code&gt;) a value to a key.  It takes 2 arguments: the key and the value, and is expected to return the value.  It functionally defaults to &lt;code&gt;object.AT-KEY(key) = value&lt;/code&gt;.  A typical reason for implementing this method is performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# same as @a.ASSIGN-KEY("bar", 42)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  BIND-KEY
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;BIND-KEY&lt;/code&gt; method is a method that will be called when binding (&lt;code&gt;:=&lt;/code&gt;) a value to a key.  It takes 2 arguments: the key and the value, and is expected to return the value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# same as %h.BIND-KEY("bar", 42)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  STORE
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;STORE&lt;/code&gt; method accepts the values (as an &lt;a href="https://docs.raku.org/type/Iterable" rel="noopener noreferrer"&gt;&lt;code&gt;Iterable&lt;/code&gt;&lt;/a&gt;) with which to (re-)initialize the hash, &lt;strong&gt;and&lt;/strong&gt; returns the invocant.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;:INITIALIZE&lt;/code&gt; named argument will be passed with a &lt;code&gt;True&lt;/code&gt; value if this is the first time the values are to be set.  This is important if your data structure is supposed to be immutable: if that argument is &lt;code&gt;False&lt;/code&gt; or not specified, it means a re-initialization is being attempted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# same as %h.STORE( (a =&amp;gt; 42, b =&amp;gt; 666) )&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  keys
&lt;/h3&gt;

&lt;p&gt;Although not an uppercase named method, it is an important interface method: the &lt;a href="https://docs.raku.org/type/Map#method_keys" rel="noopener noreferrer"&gt;&lt;code&gt;keys&lt;/code&gt;&lt;/a&gt; method is expected to return the keys in the object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# (a b)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Handling simple customizations
&lt;/h2&gt;

&lt;p&gt;Again, that's a lot to take in (especially if you didn't read the previous post)!  But if it is just a simple customization you wish to do to the basic functionality of e.g. a hash, you can simply inherit from the &lt;code&gt;Hash&lt;/code&gt; class.  Here's a simple, contrived example that will return any values doubled as string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nn"&gt;Hash::&lt;/span&gt;&lt;span class="nv"&gt;Twice&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;Hash&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;AT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;callsame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nn"&gt;Hash::&lt;/span&gt;&lt;span class="nv"&gt;Twice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;: %h{&lt;/span&gt;&lt;span class="si"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will show:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a: 4242
b: 666666
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in this case the &lt;a href="https://docs.raku.org/syntax/callsame" rel="noopener noreferrer"&gt;&lt;code&gt;callsame&lt;/code&gt;&lt;/a&gt; function is called to get the actual value from the array.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful modules
&lt;/h2&gt;

&lt;p&gt;If you want to be able to do more than just simple modifications, but for instance have an existing data structure on which you want to provide an &lt;code&gt;Associative&lt;/code&gt; interface, it becomes a bit more complicated and potentially cumbersome.&lt;/p&gt;

&lt;p&gt;Fortunately there are a number of modules in the ecosystem that will help you to create a consistent &lt;code&gt;Associative&lt;/code&gt; interface for your class.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hash::Agnostic
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://raku.land/zef:lizmat/Hash::Agnostic" rel="noopener noreferrer"&gt;&lt;code&gt;Hash::Agnostic&lt;/code&gt;&lt;/a&gt; distribution provides a &lt;code&gt;Hash::Agnostic&lt;/code&gt; role with all of the necessary logic for making your object act as a &lt;code&gt;Hash&lt;/code&gt;.  The only methods that &lt;em&gt;must&lt;/em&gt; be provided, are the &lt;code&gt;AT-KEY&lt;/code&gt; and &lt;code&gt;keys&lt;/code&gt; methods.  Your class &lt;em&gt;may&lt;/em&gt; provide more methods for functionality or performance reasons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Map::Agnostic
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://raku.land/zef:lizmat/Map::Agnostic" rel="noopener noreferrer"&gt;&lt;code&gt;Map::Agnostic&lt;/code&gt;&lt;/a&gt; distribution provides a &lt;code&gt;Map::Agnostic&lt;/code&gt; role with all of the necessary logic for making your object act as a &lt;code&gt;Map&lt;/code&gt;.  The only methods that you &lt;em&gt;must&lt;/em&gt; be provided, are the &lt;code&gt;AT-KEY&lt;/code&gt; and &lt;code&gt;keys&lt;/code&gt; methods.  As with &lt;code&gt;Hash::Agnostic&lt;/code&gt;, your class &lt;em&gt;may&lt;/em&gt; provide more methods for functionality or performance reasons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example class
&lt;/h3&gt;

&lt;p&gt;A very contrived example in which a &lt;code&gt;Hash::Int&lt;/code&gt; class is created that provides an &lt;code&gt;Associative&lt;/code&gt; interface in which the keys can only be integer values.  Under the hood it uses an array to store values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Hash::&lt;/span&gt;&lt;span class="nv"&gt;Agnostic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;class&lt;/span&gt; &lt;span class="nn"&gt;Hash::&lt;/span&gt;&lt;span class="nv"&gt;Int&lt;/span&gt; &lt;span class="nv"&gt;does&lt;/span&gt; &lt;span class="nn"&gt;Hash::&lt;/span&gt;&lt;span class="nv"&gt;Agnostic&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;has&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;AT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Int:D&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;AT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;POS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;method&lt;/span&gt; &lt;span class="nb"&gt;keys&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="o"&gt;^&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;EXISTS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;POS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$_&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="nv"&gt;method&lt;/span&gt; &lt;span class="nv"&gt;STORE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@values&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;CREATE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;STORE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;INITIALIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;@values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;ASSIGN&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;POS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;values&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@values&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and can be used like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nn"&gt;Hash::&lt;/span&gt;&lt;span class="nv"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt; &lt;span class="nv"&gt;b&lt;/span&gt; &lt;span class="mi"&gt;137&lt;/span&gt; &lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;dd&lt;/span&gt; &lt;span class="nv"&gt;%h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which would show:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a
Hash::Int.new(42 =&amp;gt; "a",137 =&amp;gt; "c",666 =&amp;gt; "b")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, note that the &lt;code&gt;STORE&lt;/code&gt; method had to be provided by the class to allow for the &lt;code&gt;is Hash::Int&lt;/code&gt; syntax to work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're wondering what's happening with &lt;code&gt;Map.CREATE.STORE(values, :INITIALIZE)&lt;/code&gt;: the initialization logic of hashes and maps allows for both separate key,value initialization, as well as key=&amp;gt;value initialization.  And any mix of them.  So this is just a quick way to use that rather specialized logic of &lt;code&gt;Map.new&lt;/code&gt; to create a consistent &lt;a href="https://docs.raku.org/type/Seq" rel="noopener noreferrer"&gt;&lt;code&gt;Seq&lt;/code&gt;&lt;/a&gt; of &lt;a href="https://docs.raku.org/type/Pair" rel="noopener noreferrer"&gt;&lt;code&gt;Pair&lt;/code&gt;&lt;/a&gt;s with which to initialize the underlying array.&lt;/p&gt;

&lt;p&gt;Raku actually has a syntax for creating a &lt;code&gt;Hash&lt;/code&gt; that only takes &lt;code&gt;Int&lt;/code&gt; values as keys: &lt;code&gt;my %h{Int}&lt;/code&gt;.  This creates a so-called &lt;a href="https://docs.raku.org/language/hashmap#Non-string_keys_(object_hash)" rel="noopener noreferrer"&gt;"object hash"&lt;/a&gt; with different performance characteristics to the approach taken with &lt;code&gt;Hash::Int&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This concludes the tenth episode of cases of UPPER language elements in the Raku Programming Language, the third episode discussing interface methods.&lt;/p&gt;

&lt;p&gt;In this episode the &lt;code&gt;AT-KEY&lt;/code&gt; family of methods were described, as well as some simple customizations and  some handy Raku modules that can help you create a fully functional interface: &lt;code&gt;Map::Agnostic&lt;/code&gt; and &lt;code&gt;Hash::Agnostic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next episode!&lt;/p&gt;

</content>
    <author>
      <name>Elizabeth Mattijsen</name>
    </author>
    <id>https://dev.to/lizmat/associative-methods-2mcl</id>
    <published>2026-02-12T19:28:15Z</published>
    <updated>2026-02-12T19:28:15Z</updated>
    <category term="rakulang"/>
    <category term="programming"/>
    <category term="tutorial"/>
  </entry>
  <entry>
    <title>E-day Logarithmic Glow-up</title>
    <link rel="alternate" href="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/" type="text/html"/>
    <content type="html">
&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Introduction&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Every year on February 7th, math enthusiasts worldwide (should) consider celebrating Euler’s Day or E-day. Among Euler’s many gifts to the (currently known) mathematical universe is the ever-popular number&amp;nbsp;&lt;strong&gt;e&lt;/strong&gt;, the natural logarithm base that is basically the rock star of calculus, complex analysis, continuous growth models, compound interest, and (much) more. That irrational number shows up in places we might or might not expect. This blog post (&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/E-day-logarithmic-glow-up.ipynb" target="_blank" rel="noreferrer noopener"&gt;notebook&lt;/a&gt;) explores some formulas and plots related to &lt;a href="https://en.wikipedia.org/wiki/E_(mathematical_constant)" target="_blank" rel="noreferrer noopener"&gt;Euler&amp;#8217;s number&lt;/a&gt;,&amp;nbsp;&lt;strong&gt;e&lt;/strong&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;The code of the fractal plots is Raku translation of the Wolfram Language code in the notebook&amp;nbsp;&lt;a href="https://community.wolfram.com/groups/-/m/t/3634481"&gt;&amp;#8220;Celebrating Euler&amp;#8217;s day: algorithms for derangements, branch cuts, and exponential fractals&amp;#8221;&lt;/a&gt;&amp;nbsp;by Ed Pegg.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Setup&lt;/h2&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;use JavaScript::D3;&lt;/div&gt;&lt;div class="cm-line"&gt;use JavaScript::D3::Utilities;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% javascript&lt;/div&gt;&lt;div class="cm-line"&gt;require.config({&lt;/div&gt;&lt;div class="cm-line"&gt;     paths: {&lt;/div&gt;&lt;div class="cm-line"&gt;     d3: &amp;apos;https://d3js.org/d3.v7.min&amp;apos;&lt;/div&gt;&lt;div class="cm-line"&gt;}});&lt;/div&gt;&lt;div class="cm-line"&gt; &lt;/div&gt;&lt;div class="cm-line"&gt;require([&amp;apos;d3&amp;apos;], function(d3) {&lt;/div&gt;&lt;div class="cm-line"&gt;     console.log(d3);&lt;/div&gt;&lt;div class="cm-line"&gt;});&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot(10.rand xx 40, background =&amp;gt; &amp;apos;none&amp;apos;, stroke-width =&amp;gt; 2)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $title-color = &amp;apos;Silver&amp;apos;;&lt;/div&gt;&lt;div class="cm-line"&gt;my $background = &amp;apos;#1F1F1F&amp;apos;;&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Formulas and computation&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Raku has the built in mathematical constant&amp;nbsp;&amp;nbsp;(base of the natural logarithm). Both ASCII &amp;#8220;e&amp;#8221; and Unicode &amp;#8220;𝑒&amp;#8221; (&amp;#8220;MATHEMATICAL ITALIC SMALL E&amp;#8221; or&amp;nbsp;&lt;code&gt;U+1D452&lt;/code&gt;) can be used:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;[e, 𝑒]&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# [2.718281828459045 2.718281828459045]&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;We can verify this famous equation:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;e ** (i * π) + 1&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 0+1.2246467991473532e-16i&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Let us compute&amp;nbsp;&amp;nbsp;using the canonical formula:&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img data-attachment-id="1675" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/screenshot-2026-02-07-at-10-20-36-pm/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.36-pm.png" data-orig-size="216,133" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2026-02-07 at 10.20.36 PM" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.36-pm.png?w=216" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.36-pm.png?w=216" loading="lazy" width="216" height="133" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.36-pm.png?w=216" alt="" class="wp-image-1675" style="width:175px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.36-pm.png 216w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.36-pm.png?w=150 150w" sizes="(max-width: 216px) 100vw, 216px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Here is the corresponding Raku code:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my @e-terms = ([\*] 1.FatRat .. *);&lt;/div&gt;&lt;div class="cm-line"&gt;my $e-by-sum = 1 + (1 «/» @e-terms[0 .. 100]).sum&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381312&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we compute the&amp;nbsp;&lt;code&gt;e&lt;/code&gt;&amp;nbsp;using Wolfram Language (via&amp;nbsp;&lt;a href="https://www.wolfram.com/wolframscript"&gt;&lt;code&gt;wolframscript&lt;/code&gt;&lt;/a&gt;):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $proc = run &amp;apos;wolframscript&amp;apos;, &amp;apos;--code&amp;apos;, &amp;apos;N[E, 100]&amp;apos;, :out;&lt;/div&gt;&lt;div class="cm-line"&gt;my $e-wl = $proc.out.slurp(:close).substr(0,*-6).FatRat&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274661651602106&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Side-by-side comparison:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% html&lt;/div&gt;&lt;div class="cm-line"&gt;[ &lt;/div&gt;&lt;div class="cm-line"&gt;    {lang =&amp;gt; &amp;apos;Raku&amp;apos;, value =&amp;gt; $e-by-sum.Str.substr(0,100)},&lt;/div&gt;&lt;div class="cm-line"&gt;    {lang =&amp;gt; &amp;apos;Wolfram Language&amp;apos;, value =&amp;gt; $e-wl.Str.substr(0,100)}&lt;/div&gt;&lt;div class="cm-line"&gt;]&lt;/div&gt;&lt;div class="cm-line"&gt;==&amp;gt; to-html(field-names =&amp;gt; &amp;lt;lang value&amp;gt;, align =&amp;gt; &amp;apos;left&amp;apos;)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;lang&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Raku&lt;/td&gt;&lt;td&gt;2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wolfram Language&lt;/td&gt;&lt;td&gt;2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;And here is the absolute difference:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;abs($e-by-sum - $e-wl).Num&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# 2.2677179245992183e-106&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Let us next compute&amp;nbsp;&lt;code&gt;e&lt;/code&gt;&amp;nbsp;using the continued fraction formula:&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img data-attachment-id="1676" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/screenshot-2026-02-07-at-10-20-27-pm/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.27-pm.png" data-orig-size="604,309" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2026-02-07 at 10.20.27 PM" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.27-pm.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.27-pm.png?w=604" loading="lazy" width="604" height="309" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.27-pm.png?w=604" alt="" class="wp-image-1676" style="width:430px;height:auto" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.27-pm.png 604w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.27-pm.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/screenshot-2026-02-07-at-10.20.27-pm.png?w=300 300w" sizes="(max-width: 604px) 100vw, 604px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;To make the corresponding continued fraction we first generate its sequence using Philippe Deléham formula for&amp;nbsp;&lt;a href="https://oeis.org/A003417"&gt;OEIS sequence A003417&lt;/a&gt;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my @rec = 2, 1, 2, 1, 1, 4, 1, 1, -1 * * + 0 * * + 0 * * + 2 * * + 0 * * + 0 * * ... Inf;&lt;/div&gt;&lt;div class="cm-line"&gt;@rec[^20]&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;# (2 1 2 1 1 4 1 1 6 1 1 8 1 1 10 1 1 12 1 1)&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here is a function that computes the continuous fraction formula:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;sub e-by-cf(UInt:D $i) { @rec[^$i].reverse».FatRat.reduce({$^b + 1 / $^a}) }&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;A more generic continued fraction computation is given in&amp;nbsp;&lt;a href="https://rosettacode.org/wiki/Continued_fraction#Raku"&gt;the Raku entry&lt;/a&gt;&amp;nbsp;for&amp;nbsp;&lt;a href="https://rosettacode.org/wiki/Continued_fraction"&gt;&amp;#8220;Continued fraction&amp;#8221;&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Let us compare all three results:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% html&lt;/div&gt;&lt;div class="cm-line"&gt;[ &lt;/div&gt;&lt;div class="cm-line"&gt;    {lang =&amp;gt; &amp;apos;Raku&amp;apos;, formula =&amp;gt; &amp;apos;sum&amp;apos;, value =&amp;gt; $e-by-sum.Str.substr(0,100)},&lt;/div&gt;&lt;div class="cm-line"&gt;    {lang =&amp;gt; &amp;apos;Raku&amp;apos;, formula =&amp;gt; &amp;apos;cont. fraction&amp;apos;, value =&amp;gt; &amp;amp;e-by-cf(150).Str.substr(0,100)},&lt;/div&gt;&lt;div class="cm-line"&gt;    {lang =&amp;gt; &amp;apos;WL&amp;apos;, formula =&amp;gt; &amp;apos;-&amp;apos;, value =&amp;gt; $e-wl.Str.substr(0,100)}&lt;/div&gt;&lt;div class="cm-line"&gt;]&lt;/div&gt;&lt;div class="cm-line"&gt;==&amp;gt; to-html(field-names =&amp;gt; &amp;lt;lang formula value&amp;gt;, align =&amp;gt; &amp;apos;left&amp;apos;)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;lang&lt;/th&gt;&lt;th&gt;formula&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Raku&lt;/td&gt;&lt;td&gt;sum&lt;/td&gt;&lt;td&gt;2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Raku&lt;/td&gt;&lt;td&gt;cont. fraction&lt;/td&gt;&lt;td&gt;2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WL&lt;/td&gt;&lt;td&gt;&amp;#8211;&lt;/td&gt;&lt;td&gt;2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Plots&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;The maximum of the function&amp;nbsp;&lt;em&gt;x^(1/x)&lt;/em&gt;&amp;nbsp;is attained at&amp;nbsp;&lt;code&gt;e&lt;/code&gt;:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot((1, 1.01 ... 5).map({ [$_, $_ ** (1/$_)] }), :$background, stroke-width =&amp;gt; 4, :grid-lines)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="1665" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/max-at-exp-dark/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png" data-orig-size="849,565" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Max-at-Exp-dark" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png?w=849" loading="lazy" width="849" height="565" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png" alt="" class="wp-image-1665" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png 849w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png?w=150&amp;amp;h=100 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png?w=300&amp;amp;h=200 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/max-at-exp-dark.png?w=768&amp;amp;h=511 768w" sizes="(max-width: 849px) 100vw, 849px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;The Exponential spiral is based on the exponential function (and below it is compared to the&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Archimedean_spiral"&gt;Archimedean spiral&lt;/a&gt;):&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;my @log-spiral = (0, 0.1 ... 12 * π).map({ e ** ($_/12) «*» [cos($_), sin($_)] });&lt;/div&gt;&lt;div class="cm-line"&gt;my @arch-spiral = (0, 0.1 ... 12 * π).map({ 2 * $_ «*» [cos($_), sin($_)] });&lt;/div&gt;&lt;div class="cm-line"&gt;my %opts = stroke-width =&amp;gt; 4, :!axes, :!grid-lines, :400width, :350height, :$title-color;&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot(@log-spiral, :$background, color =&amp;gt; &amp;apos;red&amp;apos;, title =&amp;gt; &amp;apos;Exponential spiral&amp;apos;, |%opts) ~&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot(@arch-spiral, :$background, color =&amp;gt; &amp;apos;blue&amp;apos;, title =&amp;gt; &amp;apos;Archimedean spiral&amp;apos;, |%opts)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="1667" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/exp-and-archemedian-spirals-dark/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png" data-orig-size="1122,495" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Exp-and-Archemedian-spirals-dark" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png?w=1008" loading="lazy" width="1122" height="495" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png" alt="" class="wp-image-1667" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png 1122w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png?w=150&amp;amp;h=66 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png?w=300&amp;amp;h=132 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png?w=768&amp;amp;h=339 768w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-and-archemedian-spirals-dark.png?w=1024&amp;amp;h=452 1024w" sizes="(max-width: 1122px) 100vw, 1122px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://mathworld.wolfram.com/Catenary.html"&gt;Catenary&lt;/a&gt;&amp;nbsp;is the curve a hanging flexible wire or chain assumes when supported at its ends and acted upon by a uniform gravitational force. It is given with the formula:&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Here is a corresponding plot:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot((-1, -0.99 ... 1).map({ [$_, e ** $_ + e ** (-$_)] }), :$background, stroke-width =&amp;gt; 4, :grid-lines, title =&amp;gt; &amp;apos;Catenary curve&amp;apos;, :$title-color)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="1666" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/catenary-curve-dark/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png" data-orig-size="859,586" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Catenary-curve-dark" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png?w=859" loading="lazy" width="859" height="586" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png" alt="" class="wp-image-1666" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png 859w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png?w=150&amp;amp;h=102 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png?w=300&amp;amp;h=205 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/catenary-curve-dark.png?w=768&amp;amp;h=524 768w" sizes="(max-width: 859px) 100vw, 859px" /&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Fractals&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;The exponential curlicue fractal:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#%js&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-list-line-plot(angle-path(e &amp;lt;&amp;lt;*&amp;gt;&amp;gt; (1...15_000)), :$background, :!axes, :400width, :600height)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="1668" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/curlicue-fractal-dark/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/curlicue-fractal-dark.png" data-orig-size="556,845" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Curlicue-fractal-dark" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/curlicue-fractal-dark.png?w=197" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/curlicue-fractal-dark.png?w=556" loading="lazy" width="556" height="845" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/curlicue-fractal-dark.png" alt="" class="wp-image-1668" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/curlicue-fractal-dark.png 556w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/curlicue-fractal-dark.png?w=99&amp;amp;h=150 99w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/curlicue-fractal-dark.png?w=197&amp;amp;h=300 197w" sizes="(max-width: 556px) 100vw, 556px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Here is a plot of exponential Mandelbrot set:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $h = 0.01;&lt;/div&gt;&lt;div class="cm-line"&gt;my @table = do for -2.5, -2.5 + $h ... 2.5 -&amp;gt; $x {&lt;/div&gt;&lt;div class="cm-line"&gt;    do for -1, -1 + $h ... 4  -&amp;gt; $y {&lt;/div&gt;&lt;div class="cm-line"&gt;        my $z = 0;&lt;/div&gt;&lt;div class="cm-line"&gt;        my $count = 0;&lt;/div&gt;&lt;div class="cm-line"&gt;        while $count &amp;lt; 30 &amp;amp;&amp;amp; $z.abs &amp;lt; 10e12 {&lt;/div&gt;&lt;div class="cm-line"&gt;            $z = exp($z) + $y + $x * i;&lt;/div&gt;&lt;div class="cm-line"&gt;            $count++;&lt;/div&gt;&lt;div class="cm-line"&gt;        }&lt;/div&gt;&lt;div class="cm-line"&gt;        $count - 1;&lt;/div&gt;&lt;div class="cm-line"&gt;    }&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;deduce-type(@table)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-matrix-plot(@table, :!grid-lines, color-palette =&amp;gt; &amp;apos;Rainbow&amp;apos;, :!tooltip, :!mesh)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="1670" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/exp-mandelbrot-fractal-1/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png" data-orig-size="867,861" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Exp-Mandelbrot-fractal-1" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png?w=867" loading="lazy" width="867" height="861" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png" alt="" class="wp-image-1670" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png 867w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png?w=150&amp;amp;h=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png?w=300&amp;amp;h=298 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-mandelbrot-fractal-1.png?w=768&amp;amp;h=763 768w" sizes="(max-width: 867px) 100vw, 867px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;A fractal variant using reciprocal:&lt;/p&gt;


&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;my $h = 0.0025;&lt;/div&gt;&lt;div class="cm-line"&gt;my @table = do for -1/2, -1/2 + $h ... 1/6 -&amp;gt; $x {&lt;/div&gt;&lt;div class="cm-line"&gt;    do for -1/2, -1/2 + $h ... 1/2 -&amp;gt; $y {&lt;/div&gt;&lt;div class="cm-line"&gt;        my $z = $x + $y * i;&lt;/div&gt;&lt;div class="cm-line"&gt;        my $count = 0;&lt;/div&gt;&lt;div class="cm-line"&gt;        while $count &amp;lt; 10 &amp;amp;&amp;amp; $z.abs &amp;lt; 100000 {&lt;/div&gt;&lt;div class="cm-line"&gt;            $z = exp(1 / $z);&lt;/div&gt;&lt;div class="cm-line"&gt;            $count++;&lt;/div&gt;&lt;div class="cm-line"&gt;        }&lt;/div&gt;&lt;div class="cm-line"&gt;        $count;&lt;/div&gt;&lt;div class="cm-line"&gt;    }&lt;/div&gt;&lt;div class="cm-line"&gt;}&lt;/div&gt;&lt;div class="cm-line"&gt;&lt;/div&gt;&lt;div class="cm-line"&gt;deduce-type(@table)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="wp-block-code"&gt;
	&lt;div class="cm-editor"&gt;
		&lt;div class="cm-scroller"&gt;
			
&lt;pre&gt;
&lt;code&gt;&lt;div class="cm-line"&gt;#% js&lt;/div&gt;&lt;div class="cm-line"&gt;js-d3-matrix-plot(@table, :!grid-lines, color-palette =&amp;gt; &amp;apos;Rainbow&amp;apos;, :!tooltip, :!mesh)&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="1669" data-permalink="https://rakuforprediction.wordpress.com/2026/02/07/e-day-logarithmic-glow-up/exp-reciprocal-fractal/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png" data-orig-size="865,575" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Exp-reciprocal-fractal" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png?w=865" loading="lazy" width="865" height="575" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png" alt="" class="wp-image-1669" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png 865w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png?w=150&amp;amp;h=100 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png?w=300&amp;amp;h=199 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2026/02/exp-reciprocal-fractal.png?w=768&amp;amp;h=511 768w" sizes="(max-width: 865px) 100vw, 865px" /&gt;&lt;/figure&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Every year on February 7th, math enthusiasts worldwide (should) consider celebrating Euler’s Day or E-day. Among Euler’s many gifts to the (currently known) mathematical universe is the ever-popular number e, the natural logarithm base that is basically the rock star of calculus, complex analysis, continuous growth models, compound interest, and (much) more. That irrational number shows up in places we might or might not expect. This blog post explores some formulas and plots related to Euler's number, e.</div>
    </summary>
    <author>
      <name>Anton Antonov Antonov</name>
    </author>
    <id>http://rakuforprediction.wordpress.com/?p=1661</id>
    <published>2026-02-07T23:20:47Z</published>
    <updated>2026-02-07T23:20:47Z</updated>
    <category term="D3.js"/>
    <category term="Generative Art"/>
    <category term="JavaScript"/>
    <category term="Mathematica"/>
    <category term="Number Theory"/>
    <category term="Visualization and Graphics"/>
    <category term="Continuous fractions"/>
    <category term="E-day"/>
    <category term="Euler's number"/>
    <category term="Raku"/>
  </entry>
  <entry>
    <title> Rakudo compiler, Release #189 (2026.01)</title>
    <link rel="alternate" href="https://rakudo.org/post/announce-rakudo-release-2026.01" type="text/html"/>
    <id>https://rakudo.org/post/announce-rakudo-release-2026.01</id>
    <published>2026-01-24T00:00:00Z</published>
    <updated>2026-01-24T00:00:00Z</updated>
  </entry>
  <entry>
    <title>DTAP - super simple testing protocol for infrastructure audit</title>
    <link rel="alternate" href="https://dev.to/melezhik/dtap-super-simple-testing-protocol-for-infrastructure-audit-2l45" type="text/html"/>
    <content type="html">&lt;p&gt;&lt;a href="http://doubletap.sparrowhub.io" rel="noopener noreferrer"&gt;DTAP&lt;/a&gt; is a new testing protocol allowing to test infrastructure with just a Bash scripts. Here is a quick example, let's test that &lt;code&gt;/etc/dhcp/&lt;/code&gt; directory and &lt;code&gt;/etc/dhcpcd.conf&lt;/code&gt; file exists:&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="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;ls&lt;/span&gt; /etc/dhcp/ 2&amp;gt;&amp;amp;1 | dtap &lt;span class="nt"&gt;--box&lt;/span&gt; - &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--session&lt;/span&gt; &lt;span class="nv"&gt;$session&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/dhcp/ &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--check&lt;/span&gt; path-ok &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--desc&lt;/span&gt; &lt;span class="s2"&gt;"dhcp/ dir"&lt;/span&gt;

&lt;span class="nb"&gt;ls&lt;/span&gt; /etc/dhcpcd.conf  2&amp;gt;&amp;amp;1 | dtap &lt;span class="nt"&gt;--box&lt;/span&gt; - &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--session&lt;/span&gt; &lt;span class="nv"&gt;$session&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/dhcpcd.conf &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--check&lt;/span&gt; path-ok &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--desc&lt;/span&gt; &lt;span class="s2"&gt;"dhcpcd.conf file"&lt;/span&gt;

dtap  &lt;span class="nt"&gt;--report&lt;/span&gt;  &lt;span class="nt"&gt;--session&lt;/span&gt; &lt;span class="nv"&gt;$session&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DTAP report
session: 1767875428
===
dhcp/ dir ...... OK
dhcpcd.conf file ...... OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plain and simple&lt;/p&gt;




&lt;p&gt;As one can see test scripts are just plain Bash commands, no fancy YAML or even high level programming languages.&lt;/p&gt;

&lt;p&gt;Also DTAP follows WYSIWYG principle when we get exactly what we see, in a sense this is something we would do trying to check existence  of the mentioned directory and file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls /etc/dhcp/
ls /etc/dhcpcd.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if any errors occurr we will get exactly what we are asking for - output of &lt;code&gt;ls&lt;/code&gt; command which most of the Linux users probably are familiar with:&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;/bin/bash
&lt;span class="nb"&gt;ls&lt;/span&gt;  /etc/does-not-exist 2&amp;gt;&amp;amp;1 | dtap &lt;span class="nt"&gt;--box&lt;/span&gt; - &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--session&lt;/span&gt; &lt;span class="nv"&gt;$session&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/does-not-exist &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--check&lt;/span&gt; path-ok &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--desc&lt;/span&gt; &lt;span class="s2"&gt;"/etc/does-not-exist dir"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DTAP report
session: 1767875841
===
/etc/does-not-exist dir ...... FAIL
[report]
15:37:22 :: [sparrowtask] - run sparrow task .@path=/etc/does-not-exist
15:37:22 :: [sparrowtask] - run [.], thing: .@path=/etc/does-not-exist
[task run: task.bash - .]
[task stdout]
15:37:23 :: ls: cannot access '/etc/does-not-exist': No such file or directory
[task check]
stdout match &amp;lt;^^ "/etc/does-not-exist"  $$&amp;gt; False
=================
TASK CHECK FAIL
2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;How this works?&lt;/p&gt;

&lt;p&gt;There are two essentials primitives in DTAP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;boxes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and - checks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Box is an abstraction for everything we want to test - from web server to messages in syslog files. Boxes produces some output to be checked against check rules ( aka checks ). In the previous examples - boxe is just &lt;code&gt;ls&lt;/code&gt; command which output redirected to a certain check rule via &lt;code&gt;--box -&lt;/code&gt; notation ( meaning read box output from STDIN ). DTAP comes with some predefined boxes user can use them without writing any piece of code, but most of the time boxes - are something a user would write as a chain of Bash commands something likes that:&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="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt; 
  2&amp;gt;&amp;amp;1
  cmd1&lt;span class="p"&gt;;&lt;/span&gt;
  cmd2&lt;span class="p"&gt;;&lt;/span&gt;
  cmd3&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; | tap &lt;span class="nt"&gt;--box&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with a single script:&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="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; /some/box/script.sh | tap &lt;span class="nt"&gt;--box&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checks are rules written on formal &lt;a href="https://github.com/melezhik/Sparrow6/blob/master/documentation/taskchecks.md" rel="noopener noreferrer"&gt;DSL&lt;/a&gt; and executed remotely on DTAP server, so users don't need to install anything, only small &lt;a href="http://doubletap.sparrowhub.io/install" rel="noopener noreferrer"&gt;tap binary&lt;/a&gt; written on golang that interacts with a server send output from boxes to a server and get results back. Checks DSL is based on regular expressions and is super flexible, allowing many things to do including extension by using many general programming languages. &lt;/p&gt;

&lt;p&gt;As an example if you look inside &lt;a href="https://github.com/melezhik/doubletap/blob/main/checks/path-ok/task.check" rel="noopener noreferrer"&gt;path-ok&lt;/a&gt; check that verifies file/directory existence you'll see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator: &amp;lt;&amp;lt;OK
!bash
echo "regexp: ^^ \"$(config path)\"  \$\$"
OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;To list available checks just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tap &lt;span class="nt"&gt;--check_list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow double tap web site &lt;a href="http://doubletap.sparrowhub.io/checks" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to get details on using available checks.&lt;/p&gt;

&lt;p&gt;It's easy to create new checks and add them to DTAP distribution, if you are instead please let me know. There is quick start introduction  into check DSL could be found &lt;a href="https://git.resf.org/testing/sparrow_task_check_quick_start/src/branch/main" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Conclusion.&lt;/p&gt;

&lt;p&gt;DTAP is a new kid on the block, that allows to test infrastructure with using just a Bash yet very flexible and powerful. I encourage you to play with it, you can start with &lt;a href="http://doubletap.sparrowhub.io/install" rel="noopener noreferrer"&gt;installation&lt;/a&gt; guide&lt;/p&gt;




&lt;p&gt;Thanks for reading &lt;/p&gt;

</content>
    <author>
      <name>Alexey Melezhik</name>
    </author>
    <id>https://dev.to/melezhik/dtap-super-simple-testing-protocol-for-infrastructure-audit-2l45</id>
    <published>2026-01-08T12:54:15Z</published>
    <updated>2026-01-08T12:54:15Z</updated>
    <category term="testing"/>
    <category term="inspec"/>
    <category term="infrastructure"/>
    <category term="devops"/>
  </entry>
  <entry>
    <title>Data science over small movie dataset – Part 2</title>
    <link rel="alternate" href="https://rakuforprediction.wordpress.com/2025/12/31/data-science-over-small-movie-dataset-part-2/" type="text/html"/>
    <content type="html">
&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Introduction&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;This document (&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/Data-science-over-a-small-movie-dataset-Part-2.ipynb"&gt;notebook&lt;/a&gt;) shows transformation of movie dataset into a form more suitable for making a &lt;strong&gt;&lt;em&gt;movie recommender system&lt;/em&gt;&lt;/strong&gt;. (It builds upon &lt;a href="https://rakuforprediction.wordpress.com/2025/11/27/data-science-over-small-movie-dataset-part-1/" target="_blank" rel="noreferrer noopener"&gt;Part 1&lt;/a&gt; of the blog posts series.)&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The movie data was downloaded from&amp;nbsp;&lt;a href="https://www.kaggle.com/datasets/thedevastator/imdb-movie-ratings-dataset"&gt;&amp;#8220;IMDB Movie Ratings Dataset&amp;#8221;&lt;/a&gt;. That dataset was chosen because:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;It has the right size for demonstration of data wrangling techniques
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;≈5000 rows and 15 columns (each row corresponding to a movie)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;It is &amp;#8220;real life&amp;#8221; data with expected skewness of variable distributions&lt;/li&gt;



&lt;li&gt;It is diverse enough over movie years and genres&lt;/li&gt;



&lt;li&gt;Relatively small number of missing values&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;The full &amp;#8220;Raku for Data Science&amp;#8221; showcase is done with three notebooks, [AAn1, AAn2, AAn3]:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/Data-science-over-a-small-movie-dataset-Part-1.ipynb"&gt;Data transformations and analysis&lt;/a&gt;, [AAn1]&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/Data-science-over-a-small-movie-dataset-Part-2.ipynb"&gt;Sparse matrix recommender&lt;/a&gt;, [AAn2]&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/Data-science-over-a-small-movie-dataset-Part-3.ipynb"&gt;Relationships graphs&lt;/a&gt;, [AAn3]&lt;/li&gt;
&lt;/ol&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;All three notebooks feature the same introduction, setup, and references sections in order to make it easier for readers to browse, access, or reproduce the content.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;The series data files can be found in the folder&amp;nbsp;&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/tree/main/Data"&gt;&amp;#8220;Data&amp;#8221;&lt;/a&gt;&amp;nbsp;of the GitHub repository&amp;nbsp;&lt;a href="https://github.com/antononcube/RakuForPrediction-blog"&gt;&amp;#8220;RakuForPrediction-blog&amp;#8221;&lt;/a&gt;, [AAr1].&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The notebook series can be used in several ways:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Just reading this introduction and then browsing the notebooks&lt;/li&gt;



&lt;li&gt;Reading only this (data transformations) notebook in order to see how data wrangling is done&lt;/li&gt;



&lt;li&gt;Evaluating all three notebooks in order to learn and reproduce the computational steps in them&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Outline&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Here are the transformation, data analysis, and machine learning steps taken in the notebook series, [AAn1, AAn2, AAn3]:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;
&lt;li&gt;Ingest the data &amp;#8212; &lt;em&gt;&lt;strong&gt;Part 1&lt;/strong&gt;&lt;/em&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Shape size and summaries&lt;/li&gt;



&lt;li&gt;Numerical columns transformation&lt;/li&gt;



&lt;li&gt;Renaming columns to have more convenient names&lt;/li&gt;



&lt;li&gt;Separating the non-uniform genres column into movie-genre associations
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Into long format&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Basic data analysis &amp;#8212; &lt;em&gt;&lt;strong&gt;Part 1&lt;/strong&gt;&lt;/em&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Number of movies per year distribution&lt;/li&gt;



&lt;li&gt;Movie-genre distribution&lt;/li&gt;



&lt;li&gt;Pareto principle adherence for movie directors&lt;/li&gt;



&lt;li&gt;Correlation between number of votes and rating&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Association Rules Learning (ARL) &amp;#8212; &lt;em&gt;&lt;strong&gt;Part 1&lt;/strong&gt;&lt;/em&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Converting long format dataset into &amp;#8220;baskets&amp;#8221; of genres&lt;/li&gt;



&lt;li&gt;Most frequent combinations of genres&lt;/li&gt;



&lt;li&gt;Implications between genres
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;I.e. a biography-movie is also a drama-movie 94% of the time&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;LLM-derived dictionary of most commonly used ARL measures&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Recommender system creation &amp;#8212; &lt;em&gt;&lt;strong&gt;Part 2&lt;/strong&gt;&lt;/em&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Conversion of numerical data into categorical data&lt;/li&gt;



&lt;li&gt;Application of one hot embedding&lt;/li&gt;



&lt;li&gt;Experimenting / observing recommendation results&lt;/li&gt;



&lt;li&gt;Getting familiar with the movie data by computing profiles for sets of movies&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Relationships graphs &amp;#8212; &lt;em&gt;&lt;strong&gt;Part 3&lt;/strong&gt;&lt;/em&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Find the nearest neighbors for every movie in a certain range of years&lt;/li&gt;



&lt;li&gt;Make the corresponding nearest neighbors graph
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Using different weights for the different types of movie metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Visualize largest components&lt;/li&gt;



&lt;li&gt;Make and visualize graphs based on different filtering criteria&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Comments &amp;amp; observations&lt;/h3&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;This notebook series started as a demonstration of making a &amp;#8220;real life&amp;#8221; data Recommender System (RS).
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;The data transformations notebook would not be needed if the data had &amp;#8220;nice&amp;#8221; tabular form.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Since the data have aggregated values in its &amp;#8220;genres&amp;#8221; column typical long form transformations have to be done.&lt;/li&gt;



&lt;li&gt;On the other hand, the actor names per movie are not aggregated but spread-out in three columns.&lt;/li&gt;



&lt;li&gt;Both cases represent a single movie metadata type.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;For both long format transformations (or similar) are needed in order to make an RS.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;After a corresponding Sparse Matrix Recommender (SMR) is made its sparse matrix can be used to do additional analysis.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Such extensions are: deriving clusters, making and visualizing graphs, making and evaluating suitable classifiers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;In most &amp;#8220;real life&amp;#8221; data processing most of the data transformation listed steps above are taken.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Another exploratory data analysis demo is given in the video &lt;a href="https://www.youtube.com/watch?v=YCnjMVSfT8w"&gt;&amp;#8220;Exploratory Data Analysis with Raku&amp;#8221;&lt;/a&gt;, [AAv3].&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;ARL can be also used for deriving recommendations if the data is large enough.&lt;/li&gt;



&lt;li&gt;The SMR object is based on Nearest Neighbors finding over &amp;#8220;bags of tags.&amp;#8221;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Latent Semantic Indexing (LSI) tag-weighting functions are applied.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;The data does not have movie-viewer data, hence only item-item recommenders are created and used.&lt;/li&gt;



&lt;li&gt;One hot embedding is a common technique, which in this notebook is done via cross-tabulation.&lt;/li&gt;



&lt;li&gt;The categorization of numerical data means putting number into suitable bins or &amp;#8220;buckets.&amp;#8221;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;The bin or bucket boundaries can be on a regular grid or a quantile grid.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;For categorized numerical data one-hot embedding matrices can be processed to increase similarity between numeric buckets that are close to each to other.&lt;/li&gt;



&lt;li&gt;Nearest-neighbors based recommenders &amp;#8212; like SMR &amp;#8212; can be used as classifiers.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;These are the so called K-Nearest Neighbors (KNN) classifiers.&lt;/li&gt;



&lt;li&gt;Although the data is small (both row-wise &amp;amp; column-wise) we can consider making classifiers predicting IMDB ratings or number of votes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Using the recommender matrix similarities between different movies can be computed and a corresponding graph can be made.&lt;/li&gt;



&lt;li&gt;Centrality analysis and simulations of random walks over the graph can be made.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Like Google&amp;#8217;s &amp;#8220;Page-rank&amp;#8221; algorithm.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;The relationship graphs can be used to visualize the &amp;#8220;structure&amp;#8221; of movie dataset.&lt;/li&gt;



&lt;li&gt;Alternatively, clustering can be used.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Hierarchical clustering might be of interest.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;If the movies had reviews or summaries associated with them, then Latent Semantic Analysis (LSA) could be applied.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;SMR can use both LSA-terms-based and LSA-topics-based representations of the movies.&lt;/li&gt;



&lt;li&gt;LLMs can be used to derive the LSA representation.&lt;/li&gt;



&lt;li&gt;Again, &lt;em&gt;not done in these series of notebooks&lt;/em&gt;.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;See, the video &lt;a href="https://www.youtube.com/watch?v=JHO2Wk1b-Og"&gt;&amp;#8220;Raku RAG demo&amp;#8221;&lt;/a&gt;, [AAv4], for such demonstration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Setup&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Load packages used in the notebook:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
use Math::SparseMatrix;
use ML::SparseMatrixRecommender;
use ML::SparseMatrixRecommender::Utilities;
use Statistics::OutlierIdentifiers;

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% javascript
require.config({
     paths: {
     d3: 'https://d3js.org/d3.v7.min'
}});

require(&amp;#91;'d3'], function(d3) {
     console.log(d3);
});

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% js
js-d3-list-line-plot(10.rand xx 40, background =&amp;gt; 'none', stroke-width =&amp;gt; 2)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $title-color = 'Silver';
my $stroke-color = 'SlateGray';
my $tooltip-color = 'LightBlue';
my $tooltip-background-color = 'none';
my $tick-labels-font-size = 10;
my $tick-labels-color = 'Silver';
my $tick-labels-font-family = 'Helvetica';
my $background = '#1F1F1F';
my $color-scheme = 'schemeTableau10';
my $color-palette = 'Inferno';
my $edge-thickness = 3;
my $vertex-size = 6;
my $mmd-theme = q:to/END/;
%%{
  init: {
    'theme': 'forest',
    'themeVariables': {
      'lineColor': 'Ivory'
    }
  }
}%%
END
my %force = collision =&amp;gt; {iterations =&amp;gt; 0, radius =&amp;gt; 10},link =&amp;gt; {distance =&amp;gt; 180};
my %force2 = charge =&amp;gt; {strength =&amp;gt; -30, iterations =&amp;gt; 4}, collision =&amp;gt; {radius =&amp;gt; 50, iterations =&amp;gt; 4}, link =&amp;gt; {distance =&amp;gt; 30};

my %opts = :$background, :$title-color, :$edge-thickness, :$vertex-size;

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# {background =&amp;gt; #1F1F1F, edge-thickness =&amp;gt; 3, title-color =&amp;gt; Silver, vertex-size =&amp;gt; 6}

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Ingest data&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Download from GitHub the files:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Data/movie_data.csv.zip"&gt;https://github.com/antononcube/RakuForPrediction-blog/blob/main/Data/movie_data.csv.zip&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Data/dsMovieDataLongForm.csv.zip"&gt;https://github.com/antononcube/RakuForPrediction-blog/blob/main/Data/dsMovieDataLongForm.csv.zip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;And unzip them.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Ingest movie data:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $fileName = $*HOME ~ '/Downloads/movie_data.csv';
my @dsMovieData=data-import($fileName, headers=&amp;gt;'auto');
@dsMovieData .= map({ $_&amp;lt;title_year&amp;gt; = $_&amp;lt;title_year&amp;gt;.Int.Str; $_});
deduce-type(@dsMovieData)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Vector(Assoc(Atom((Str)), Atom((Str)), 15), 5043)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here is a sample of the movie data over the columns we most interested in:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% html
my @movie-columns = &amp;lt;index movie_title title_year genres imdb_score num_voted_users&amp;gt;;
@dsMovieData.pick(4)
==&amp;gt; to-html(field-names =&amp;gt; @movie-columns)

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;index&lt;/th&gt;&lt;th&gt;movie_title&lt;/th&gt;&lt;th&gt;title_year&lt;/th&gt;&lt;th&gt;genres&lt;/th&gt;&lt;th&gt;imdb_score&lt;/th&gt;&lt;th&gt;num_voted_users&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;3322&lt;/td&gt;&lt;td&gt;Veronika Decides to Die&lt;/td&gt;&lt;td&gt;2009&lt;/td&gt;&lt;td&gt;Drama|Romance&lt;/td&gt;&lt;td&gt;6.5&lt;/td&gt;&lt;td&gt;10100&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1511&lt;/td&gt;&lt;td&gt;The Maze Runner&lt;/td&gt;&lt;td&gt;2014&lt;/td&gt;&lt;td&gt;Action|Mystery|Sci-Fi|Thriller&lt;/td&gt;&lt;td&gt;6.8&lt;/td&gt;&lt;td&gt;310903&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1301&lt;/td&gt;&lt;td&gt;Big Miracle&lt;/td&gt;&lt;td&gt;2012&lt;/td&gt;&lt;td&gt;Biography|Drama|Romance&lt;/td&gt;&lt;td&gt;6.5&lt;/td&gt;&lt;td&gt;15231&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;55&lt;/td&gt;&lt;td&gt;The Good Dinosaur&lt;/td&gt;&lt;td&gt;2015&lt;/td&gt;&lt;td&gt;Adventure|Animation|Comedy|Family|Fantasy&lt;/td&gt;&lt;td&gt;6.8&lt;/td&gt;&lt;td&gt;62836&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Ingest the movie data already&amp;nbsp;&lt;em&gt;&lt;strong&gt;transformed&lt;/strong&gt;&lt;/em&gt;&amp;nbsp;in the first notebook, [AAn1]:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @dsMovieDataLongForm = data-import($*HOME ~ '/Downloads/dsMovieDataLongForm.csv', headers =&amp;gt; 'auto');
deduce-type(@dsMovieDataLongForm)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Vector(Assoc(Atom((Str)), Atom((Str)), 3), 84481)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Data summary:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @field-names = &amp;lt;Item TagType Tag&amp;gt;;
sink records-summary(@dsMovieDataLongForm, :@field-names)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# +------------------+------------------------+-------------------+
# | Item             | TagType                | Tag               |
# +------------------+------------------------+-------------------+
# | 1387    =&amp;gt; 27    | genre         =&amp;gt; 29008 | Drama    =&amp;gt; 5188  |
# | 3539    =&amp;gt; 27    | actor         =&amp;gt; 15129 | English  =&amp;gt; 4704  |
# | 902     =&amp;gt; 27    | title         =&amp;gt; 5043  | USA      =&amp;gt; 3807  |
# | 2340    =&amp;gt; 27    | reviews_count =&amp;gt; 5043  | Comedy   =&amp;gt; 3744  |
# | 839     =&amp;gt; 25    | language      =&amp;gt; 5043  | Thriller =&amp;gt; 2822  |
# | 1667    =&amp;gt; 25    | country       =&amp;gt; 5043  | Action   =&amp;gt; 2306  |
# | 466     =&amp;gt; 25    | director      =&amp;gt; 5043  | Romance  =&amp;gt; 2214  |
# | (Other) =&amp;gt; 84298 | (Other)       =&amp;gt; 15129 | (Other)  =&amp;gt; 59696 |
# +------------------+------------------------+-------------------+


&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Recommender system&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;One way to investigate (browse) the data is to make a recommender system and explore with it different aspects of the movie dataset like movie profiles and nearest neighbors similarities distribution.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Make the recommender&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;In order to make a more meaningful recommender we put the values of the different numerical variables into &amp;#8220;buckets&amp;#8221; &amp;#8212; i.e. intervals derived corresponding to the values distribution for each variable. The boundaries of the intervals can form a regular grid, correspond to quanitile values, or be specially made. Here we use quantiles:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @bucketVars = &amp;lt;score votes_count reviews_count&amp;gt;;
my @dsMovieDataLongForm2;
sink for @dsMovieDataLongForm.map(*&amp;lt;TagType&amp;gt;).unique -&amp;gt; $var {
    if $var ∈ @bucketVars {
        my %bucketizer = ML::SparseMatrixRecommender::Utilities::categorize-to-intervals(@dsMovieDataLongForm.grep(*&amp;lt;TagType&amp;gt; eq $var).map(*&amp;lt;Tag&amp;gt;)».Numeric, probs =&amp;gt; (0..6) &amp;gt;&amp;gt;/&amp;gt;&amp;gt; 6, :interval-names):pairs;
        @dsMovieDataLongForm2.append(@dsMovieDataLongForm.grep(*&amp;lt;TagType&amp;gt; eq $var).map(*.clone).map({ $_&amp;lt;Tag&amp;gt; = %bucketizer{$_&amp;lt;Tag&amp;gt;}; $_ }))
    } else {
        @dsMovieDataLongForm2.append(@dsMovieDataLongForm.grep(*&amp;lt;TagType&amp;gt; eq $var))
    }
}

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
sink records-summary(@dsMovieDataLongForm2, :@field-names, :12max-tallies)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# +------------------+------------------------+--------------------+
# | Item             | TagType                | Tag                |
# +------------------+------------------------+--------------------+
# | 902     =&amp;gt; 19    | actor         =&amp;gt; 15129 | English   =&amp;gt; 4704  |
# | 2340    =&amp;gt; 19    | genre         =&amp;gt; 14504 | USA       =&amp;gt; 3807  |
# | 1387    =&amp;gt; 19    | score         =&amp;gt; 5043  | Drama     =&amp;gt; 2594  |
# | 3539    =&amp;gt; 19    | country       =&amp;gt; 5043  | Comedy    =&amp;gt; 1872  |
# | 152     =&amp;gt; 18    | votes_count   =&amp;gt; 5043  | Thriller  =&amp;gt; 1411  |
# | 466     =&amp;gt; 18    | language      =&amp;gt; 5043  | Action    =&amp;gt; 1153  |
# | 1424    =&amp;gt; 18    | year          =&amp;gt; 5043  | Romance   =&amp;gt; 1107  |
# | 839     =&amp;gt; 18    | director      =&amp;gt; 5043  | Adventure =&amp;gt; 923   |
# | 132     =&amp;gt; 18    | title         =&amp;gt; 5043  | 6.1≤v&amp;lt;6.6 =&amp;gt; 901   |
# | 113     =&amp;gt; 18    | reviews_count =&amp;gt; 5043  | 7≤v&amp;lt;7.5   =&amp;gt; 891   |
# | 720     =&amp;gt; 18    |                        | Crime     =&amp;gt; 889   |
# | 1284    =&amp;gt; 18    |                        | 7.5≤v&amp;lt;9.5 =&amp;gt; 886   |
# | (Other) =&amp;gt; 69757 |                        | (Other)   =&amp;gt; 48839 |
# +------------------+------------------------+--------------------+


&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we make a Sparse Matrix Recommender (SMR):&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $smrObj = 
    ML::SparseMatrixRecommender.new
    .create-from-long-form(
        @dsMovieDataLongForm2, 
        item-column-name =&amp;gt; 'Item', 
        tag-type-column-name =&amp;gt; 'TagType',
        tag-column-name =&amp;gt; 'Tag',
        :add-tag-types-to-column-names)        
    .apply-term-weight-functions('IDF', 'None', 'Cosine')

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# ML::SparseMatrixRecommender(:matrix-dimensions((5043, 13825)), :density(&amp;lt;23319/23239825&amp;gt;), :tag-types(("reviews_count", "score", "votes_count", "genre", "country", "language", "actor", "director", "title", "year")))

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here are the recommender sub-matrices dimensions (rows and columns):&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
.say for $smrObj.take-matrices.deepmap(*.dimensions).sort(*.key)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# actor =&amp;gt; (5043 6256)
# country =&amp;gt; (5043 66)
# director =&amp;gt; (5043 2399)
# genre =&amp;gt; (5043 26)
# language =&amp;gt; (5043 48)
# reviews_count =&amp;gt; (5043 7)
# score =&amp;gt; (5043 7)
# title =&amp;gt; (5043 4917)
# votes_count =&amp;gt; (5043 7)
# year =&amp;gt; (5043 92)


&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Note that the sub-matrices of &amp;#8220;reviews_count&amp;#8221;, &amp;#8220;score&amp;#8221;, and &amp;#8220;votes_count&amp;#8221; have small number of columns, corresponding to the number probabilities specified when categorizing to intervals.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Enhance with one-hot embedding&lt;/h3&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $mat = $smrObj.take-matrices&amp;lt;year&amp;gt;;

my $matUp = Math::SparseMatrix.new(
    diagonal =&amp;gt; 1/2 xx ($mat.columns-count - 1), k =&amp;gt; 1, 
    row-names =&amp;gt; $mat.column-names,
    column-names =&amp;gt; $mat.column-names
);

my $matDown = $matUp.transpose;

# mat = mat + mat . matDown + mat . matDown
$mat = $mat.add($mat.dot($matUp)).add($mat.dot($matDown));

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Math::SparseMatrix(:specified-elements(14915), :dimensions((5043, 92)), :density(&amp;lt;14915/463956&amp;gt;))

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Make a new recommender with the enhanced matrices:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my %matrices = $smrObj.take-matrices;
%matrices&amp;lt;year&amp;gt; = $mat;
my $smrObj2 = ML::SparseMatrixRecommender.new(%matrices)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# ML::SparseMatrixRecommender(:matrix-dimensions((5043, 13825)), :density(&amp;lt;79829/69719475&amp;gt;), :tag-types(("genre", "title", "year", "actor", "director", "votes_count", "reviews_count", "score", "country", "language")))

&lt;/pre&gt;&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Recommendations&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Example recommendation by profile:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
sink $smrObj2
.apply-tag-type-weights({genre =&amp;gt; 2})
.recommend-by-profile(&amp;lt;genre:History year:1999&amp;gt;, 12, :!normalize)
.join-across(select-columns(@dsMovieData, @movie-columns), 'index')
.echo-value(as =&amp;gt; {to-pretty-table($_, align =&amp;gt; 'l', field-names =&amp;gt; &amp;#91;'score', |@movie-columns])})

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# +----------+-------+------------------------------------------+------------+----------------------------------------------+------------+-----------------+
# | score    | index | movie_title                              | title_year | genres                                       | imdb_score | num_voted_users |
# +----------+-------+------------------------------------------+------------+----------------------------------------------+------------+-----------------+
# | 1.887751 | 553   | Anna and the King                       | 1999       | Drama|History|Romance                        | 6.7        | 31080           |
# | 1.817476 | 215   | The 13th Warrior                        | 1999       | Action|Adventure|History                     | 6.6        | 101411          |
# | 1.567726 | 1016  | The Messenger: The Story of Joan of Arc | 1999       | Adventure|Biography|Drama|History|War        | 6.4        | 55889           |
# | 1.500264 | 2468  | One Man's Hero                          | 1999       | Action|Drama|History|Romance|War|Western     | 6.2        | 899             |
# | 1.487091 | 2308  | Topsy-Turvy                             | 1999       | Biography|Comedy|Drama|History|Music|Musical | 7.4        | 10037           |
# | 1.479006 | 4006  | La otra conquista                       | 1998       | Drama|History                                | 6.8        | 1024            |
# | 1.411933 | 492   | Thirteen Days                           | 2000       | Drama|History|Thriller                       | 7.3        | 45231           |
# | 1.312900 | 909   | Beloved                                 | 1998       | Drama|History|Horror                         | 5.9        | 6082            |
# | 1.237700 | 1931  | Elizabeth                               | 1998       | Biography|Drama|History                      | 7.5        | 75973           |
# | 1.168287 | 253   | The Patriot                             | 2000       | Action|Drama|History|War                     | 7.1        | 207613          |
# | 1.069476 | 1820  | The Newton Boys                         | 1998       | Action|Crime|Drama|History|Western           | 6.0        | 8309            |
# | 1.000000 | 4767  | America Is Still the Place              | 2015       | History                                      | 7.5        | 22              |
# +----------+-------+------------------------------------------+------------+----------------------------------------------+------------+-----------------+


&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image size-large"&gt;&lt;img data-attachment-id="1654" data-permalink="https://rakuforprediction.wordpress.com/2025/12/31/data-science-over-small-movie-dataset-part-2/collage-year-1999-landscape-bunnies-theatre/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png" data-orig-size="1536,1024" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Collage-year-1999-landscape-Bunnies-Theatre" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=1008" loading="lazy" width="1024" height="682" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=1024" alt="" class="wp-image-1654" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=1024 1024w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=300 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=768 768w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png?w=1440 1440w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-year-1999-landscape-bunnies-theatre.png 1536w" sizes="(max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Recommendation by history:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
sink $smrObj
.recommend(&amp;lt;2125 2308&amp;gt;, 12, :!normalize, :!remove-history)
.join-across(select-columns(@dsMovieData, @movie-columns), 'index')
.echo-value(as =&amp;gt; {to-pretty-table($_, align =&amp;gt; 'l', field-names =&amp;gt; &amp;#91;'score', |@movie-columns])})

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# +-----------+-------+-------------------------+------------+----------------------------------------------+------------+-----------------+
# | score     | index | movie_title             | title_year | genres                                       | imdb_score | num_voted_users |
# +-----------+-------+-------------------------+------------+----------------------------------------------+------------+-----------------+
# | 12.510011 | 2125  | Molière                | 2007       | Comedy|History                               | 7.3        | 5166            |
# | 12.510011 | 2308  | Topsy-Turvy            | 1999       | Biography|Comedy|Drama|History|Music|Musical | 7.4        | 10037           |
# | 8.364831  | 1728  | The Color of Freedom   | 2007       | Biography|Drama|History                      | 7.1        | 10175           |
# | 8.182233  | 1724  | Little Nicholas        | 2009       | Comedy|Family                                | 7.2        | 9214            |
# | 7.753039  | 3619  | Little Voice           | 1998       | Comedy|Drama|Music|Romance                   | 7.0        | 13892           |
# | 7.439471  | 2285  | Mrs Henderson Presents | 2005       | Comedy|Drama|Music|War                       | 7.1        | 13505           |
# | 7.430299  | 3404  | Made in Dagenham       | 2010       | Biography|Comedy|Drama|History               | 7.2        | 11158           |
# | 7.270637  | 1799  | A Passage to India     | 1984       | Adventure|Drama|History                      | 7.4        | 12980           |
# | 7.264810  | 3837  | The Names of Love      | 2010       | Comedy|Drama|Romance                         | 7.2        | 6304            |
# | 7.117232  | 4648  | The Hammer             | 2007       | Comedy|Romance|Sport                         | 7.3        | 5489            |
# | 7.046925  | 4871  | Shotgun Stories        | 2007       | Drama|Thriller                               | 7.3        | 7148            |
# | 7.040720  | 3194  | The House of Mirth     | 2000       | Drama|Romance                                | 7.1        | 6377            |
# +-----------+-------+-------------------------+------------+----------------------------------------------+------------+-----------------+


&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image size-large"&gt;&lt;img data-attachment-id="1655" data-permalink="https://rakuforprediction.wordpress.com/2025/12/31/data-science-over-small-movie-dataset-part-2/collage-molier-and-topsi-turvy-landscape-bunnies-theatre/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png" data-orig-size="1536,1024" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Collage-Molier-and-Topsi-turvy-landscape-Bunnies-Theatre" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=1008" loading="lazy" width="1024" height="682" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=1024" alt="" class="wp-image-1655" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=1024 1024w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=300 300w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=768 768w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png?w=1440 1440w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/collage-molier-and-topsi-turvy-landscape-bunnies-theatre.png 1536w" sizes="(max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Profiles&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Find movie IDs for a certain criteria (e.g. historic action movies):&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @movieIDs = $smrObj.recommend-by-profile(&amp;lt;genre:Action genre:History&amp;gt;, Inf, :!normalize).take-value.grep(*.value &amp;gt; 1)».key;
deduce-type(@movieIDs)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Vector(Atom((Str)), 14)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Find the profile of the movie set:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @profile = |$smrObj.profile(@movieIDs).take-value;
deduce-type(@profile)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Vector(Pair(Atom((Str)), Atom((Numeric))), 108)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Find the&amp;nbsp;&lt;em&gt;top&lt;/em&gt;&amp;nbsp;outliers in that profile:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
outlier-identifier(@profile».value, identifier =&amp;gt; &amp;amp;top-outliers o &amp;amp;quartile-identifier-parameters)
==&amp;gt; {@profile&amp;#91;$_]}()
==&amp;gt; my @profile2;

deduce-type(@profile2)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Vector(Pair(Atom((Str)), Atom((Numeric))), 26)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here is a table of the top outlier profile tags and their scores:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#%html
@profile.head(28)
==&amp;gt; { $_.map({ to-html-table(&amp;#91;$_,]) }) }()
==&amp;gt; to-html(:multi-column, :4columns, :html-elements)

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;genre:History0.9999999999999999&lt;/td&gt;&lt;td&gt;language:Mandarin0.3626315299347615&lt;/td&gt;&lt;td&gt;score:7.5≤v&amp;lt;9.50.2719736474510711&lt;/td&gt;&lt;td&gt;year:20150.18131576496738075&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;language:English0.8159209423532133&lt;/td&gt;&lt;td&gt;reviews_count:0≤v&amp;lt;370.3626315299347615&lt;/td&gt;&lt;td&gt;votes_count:5≤v&amp;lt;41200.2719736474510711&lt;/td&gt;&lt;td&gt;year:20140.18131576496738075&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;genre:Action0.46214109363846967&lt;/td&gt;&lt;td&gt;score:6.1≤v&amp;lt;6.60.36263152993476144&lt;/td&gt;&lt;td&gt;title:Hero0.18131576496738075&lt;/td&gt;&lt;td&gt;country:UK0.18131576496738075&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;genre:Adventure0.38097093240387203&lt;/td&gt;&lt;td&gt;country:USA0.36263152993476144&lt;/td&gt;&lt;td&gt;votes_count:68935≤v&amp;lt;1473170.18131576496738075&lt;/td&gt;&lt;td&gt;score:7≤v&amp;lt;7.50.18131576496738075&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;score:6.6≤v&amp;lt;70.3626315299347615&lt;/td&gt;&lt;td&gt;reviews_count:450≤v&amp;lt;50600.36263152993476144&lt;/td&gt;&lt;td&gt;reviews_count:37≤v&amp;lt;910.18131576496738075&lt;/td&gt;&lt;td&gt;votes_count:4120≤v&amp;lt;149850.18131576496738072&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;country:China0.3626315299347615&lt;/td&gt;&lt;td&gt;votes_count:147317≤v&amp;lt;16897640.2719736474510711&lt;/td&gt;&lt;td&gt;year:20020.18131576496738075&lt;/td&gt;&lt;td&gt;genre:Drama0.1320986315690731&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;votes_count:14985≤v&amp;lt;343590.3626315299347615&lt;/td&gt;&lt;td&gt;reviews_count:91≤v&amp;lt;1550.2719736474510711&lt;/td&gt;&lt;td&gt;director:Yimou Zhang0.18131576496738075&lt;/td&gt;&lt;td&gt;genre:Romance0.13001981085966202&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Plot all of profile&amp;#8217;s scores and the score outliers:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#%js
js-d3-list-plot(
    &amp;#91;|@profile».value.kv.map(-&amp;gt; $x, $y { %(:$x, :$y, group =&amp;gt; 'full profile' ) }), 
     |@profile2».value.kv.map(-&amp;gt; $x, $y { %(:$x, :$y, group =&amp;gt; 'outliers' ) })], 
    :$background,
    :300height,
    :600width
    )

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image size-large"&gt;&lt;img data-attachment-id="1657" data-permalink="https://rakuforprediction.wordpress.com/2025/12/31/data-science-over-small-movie-dataset-part-2/profile-scores-and-outliers/#main" data-orig-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/profile-scores-and-outliers.png" data-orig-size="688,367" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Profile-scores-and-outliers" data-image-description="" data-image-caption="" data-medium-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/profile-scores-and-outliers.png?w=300" data-large-file="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/profile-scores-and-outliers.png?w=688" loading="lazy" width="688" height="367" src="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/profile-scores-and-outliers.png?w=688" alt="" class="wp-image-1657" srcset="https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/profile-scores-and-outliers.png 688w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/profile-scores-and-outliers.png?w=150 150w, https://rakuforprediction.wordpress.com/wp-content/uploads/2025/12/profile-scores-and-outliers.png?w=300 300w" sizes="(max-width: 688px) 100vw, 688px" /&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;References&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Articles, blog posts&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AA1] Anton Antonov,&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/2021/12/31/introduction-to-data-wrangling-with-raku/"&gt;&amp;#8220;Introduction to data wrangling with Raku&amp;#8221;&lt;/a&gt;, (2021),&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/"&gt;RakuForPrediction at WordPress&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AA2] Anton Antonov,&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/2022/08/15/implementing-machine-learning-algorithms-in-raku-trc-2022-talk/"&gt;&amp;#8220;Implementing Machine Learning algorithms in Raku (TRC-2022 talk)&amp;#8221;&lt;/a&gt;, (2021),&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/"&gt;RakuForPrediction at WordPress&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Notebooks&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAn1] Anton Antonov,&lt;br&gt;&lt;a href="//path?"&gt;&amp;#8220;Small movie dataset analysis&amp;#8221;&lt;/a&gt;,&lt;br&gt;(2025),&lt;br&gt;&lt;a href="//path?"&gt;RakuForPrediction-blog at GitHub&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAn2] Anton Antonov,&lt;br&gt;&lt;a href="//path?"&gt;&amp;#8220;Small movie dataset recommender&amp;#8221;&lt;/a&gt;,&lt;br&gt;(2025),&lt;br&gt;&lt;a href="//path?"&gt;RakuForPrediction-blog at GitHub&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAn3] Anton Antonov,&lt;br&gt;&lt;a href="//path?"&gt;&amp;#8220;Small movie dataset graph&amp;#8221;&lt;/a&gt;,&lt;br&gt;(2025),&lt;br&gt;&lt;a href="//path?"&gt;RakuForPrediction-blog at GitHub&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Packages&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp1] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Data-Importers"&gt;Data::Importers, Raku package&lt;/a&gt;, (2024-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp2] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Data-Reshapers"&gt;Data::Reshapers, Raku package&lt;/a&gt;, (2021-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp3] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Data-Summarizers"&gt;Data::Summarizers, Raku package&lt;/a&gt;, (2021-2024),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp4] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Graph"&gt;Graph, Raku package&lt;/a&gt;, (2024-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp5] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-JavaScript-D3"&gt;JavaScript::D3, Raku package&lt;/a&gt;, (2022-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp6] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Jupyter-Chatbook"&gt;Jupyter::Chatbook, Raku package&lt;/a&gt;, (2023-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp7] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Math-SparseMatrix"&gt;Math::SparseMatrix, Raku package&lt;/a&gt;, (2024-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp8] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-ML-AssociationRuleLearning"&gt;ML::AssociationRuleLearning, Raku package&lt;/a&gt;, (2022-2024),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp9] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-ML-SparseMatrixRecommender"&gt;ML::SparseMatrixRecommender, Raku package&lt;/a&gt;, (2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp10] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Statistics-OutlierIdentifiers"&gt;Statistics::OutlierIdentifiers, Raku package&lt;/a&gt;, (2022),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Videos&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAv1] Anton Antonov,&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=p3iwPsc6e74"&gt;&amp;#8220;Simplified Machine Learning Workflows Overview (Raku-centric)&amp;#8221;&lt;/a&gt;, (2022),&amp;nbsp;&lt;a href="https://www.youtube.com/@AAA4prediction"&gt;YouTube/@AAA4prediction&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAv2] Anton Antonov,&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=efRHfjYebs4"&gt;&amp;#8220;TRC 2022 Implementation of ML algorithms in Raku&amp;#8221;&lt;/a&gt;, (2022),&amp;nbsp;&lt;a href="https://www.youtube.com/@AAA4prediction"&gt;YouTube/@AAA4prediction&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAv3] Anton Antonov,&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=YCnjMVSfT8w"&gt;&amp;#8220;Exploratory Data Analysis with Raku&amp;#8221;&lt;/a&gt;, (2024),&amp;nbsp;&lt;a href="https://www.youtube.com/@AAA4prediction"&gt;YouTube/@AAA4prediction&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAv4] Anton Antonov,&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=JHO2Wk1b-Og"&gt;&amp;#8220;Raku RAG demo&amp;#8221;&lt;/a&gt;, (2024),&amp;nbsp;&lt;a href="https://www.youtube.com/@AAA4prediction"&gt;YouTube/@AAA4prediction&lt;/a&gt;.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This document (notebook) shows transformation of movie dataset into a form more suitable for making a movie recommender system. (This part 2 of a blog post series.)</div>
    </summary>
    <author>
      <name>Anton Antonov Antonov</name>
    </author>
    <id>http://rakuforprediction.wordpress.com/?p=1651</id>
    <published>2025-12-31T20:58:58Z</published>
    <updated>2025-12-31T20:58:58Z</updated>
    <category term="Data Acquisition"/>
    <category term="Data Analysis"/>
    <category term="Literate Programming"/>
    <category term="Machine Learning"/>
    <category term="Recommender Systems"/>
    <category term="Sparse Matrix"/>
    <category term="Jupyter"/>
    <category term="Outlier detection"/>
    <category term="Raku"/>
  </entry>
  <entry>
    <title>Day 25 – Raku 2025 Review</title>
    <link rel="alternate" href="https://raku-advent.blog/2025/12/25/day-25-raku-2025-review/" type="text/html"/>
    <content type="html">CjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkhvdyB0aW1lIGZsaWVzLiBZZXQgYW5vdGhlciB5ZWFyIGhhcyBmbG93biBieS48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkxldCYjODIxNztzIGZpcnN0IHN0YXJ0IHdpdGggdGhlIHRlY2huaWNhbCBzdHVmZiwgYXMgbmVyZHMgZG8hPC9wPgoKCgo8aDMgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPlJha3VkbzwvaDM+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlJha3VkbyBzYXcgYWJvdXQgMTY1MCBjb21taXRzIChNb2FyVk0sIE5RUCwgUmFrdWRvLCBkb2MpIHRoaXMgeWVhciwgd2hpY2ggaXMgYWJvdXQgMjAlIGxlc3MgdGhhbiAyMDI0LiAgQWxsIG9mIHRoZXNlIHJlcG9zaXRvcmllcyBub3cgaGF2ZSAmIzgyMjA7bWFpbiYjODIyMTsgYXMgdGhlaXIgZGVmYXVsdCBicmFuY2ggKHJhdGhlciB0aGFuICYjODIyMDttYXN0ZXImIzgyMjE7KS48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkFib3V0IDU4JSBvZiB0aGUgUmFrdWRvIGNvbW1pdHMgd2VyZSBpbiB0aGUgZGV2ZWxvcG1lbnQgb2YgUmFrdUFTVCAodXAgZnJvbSAzMyUgaW4gMjAyNCksIG9mIHdoaWNoIG1vcmUgdGhhbiA8c3Ryb25nPjk1JTwvc3Ryb25nPiB3ZXJlIGRvbmUgYnkgPGVtPlN0ZWZhbiBTZWlmZXJ0PC9lbT4uIFRoaXMgd29yaywgdGhhdCB3YXMgc3VwcG9ydGVkIGJ5IGEgPGEgaHJlZj0iaHR0cHM6Ly9uZXdzLnBlcmxmb3VuZGF0aW9uLm9yZy9wb3N0L3NzZWlmZXJ0X3Jha3Vhc3RfZmluYWwiPlRQUkYgZ3JhbnQ8L2E+LCByZXN1bHRlZCBpbiBiZWluZyBhYmxlIHRvIGJ1aWxkIHRoZSBwYXJ0IG9mIFJha3VkbyB0aGF0JiM4MjE3O3Mgd3JpdHRlbiBpbiBSYWt1IHVzaW5nIFJha3VBU1QgKG9mdGVuIHJlZmVycmVkIHRvIGFzIHRoZSAmIzgyMjA7PHN0cm9uZz5ib290c3RyYXA8L3N0cm9uZz4mIzgyMjA7KS48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkhvd2V2ZXIgdGhlcmUgYXJlIHN0aWxsIHF1aXRlIGEgZmV3IGlzc3VlcyB0aGF0IG5lZWQgdG8gYmUgZml4ZWQgYmVmb3JlIFJha3VBU1QtYmFzZWQgUmFrdWRvIGNhbiBiZSBtYWRlIHRoZSBkZWZhdWx0LiAgQW5kIHRodXMgYmUgcmVhZHkgZm9yIHRoZSBuZXh0IGxhbmd1YWdlIGxldmVsIHJlbGVhc2UuICBTdGlsbCwgYW4gYW1hemluZyBhbW91bnQgb2Ygd29yayBkb25lIGJ5IDxlbT5TdGVmYW4gU2VpZmVydDwvZW0+LCBzbyBrdWRvcyE8L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+VW5kZXIgdGhlIGhvb2QsIGJlaGluZCB0aGUgc2NlbmVzPC9oND4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+PGVtPkdlb2ZmcmV5IEJyb2Fkd2VsbDwvZW0+IGhhcyBkb25lIGEgbWFqb3IgdXBkYXRlIG9mIHRoZSBpbnRlcm5hbCBNb2FyVk0gVW5pY29kZSB0b29scy4gQmFzZWQgb24gdGhhdCB3b3JrIDxlbT5TaGltbWVyZmFpcnk8L2VtPiBkZXZlbG9wZWQgYW4gdXBkYXRlIG9mIHRoZSBNb2FyVk0gVW5pY29kZSBzdXBwb3J0IGZyb20gMTUuMCB0byAxNy4wLiBUaGlzIGluY2x1ZGVzIHN1cHBvcnQgZm9yIHNvbWUgbmV3IGVtb2ppcyBzdWNoIGFzIEZJTkdFUlBSSU5UIDxpbWcgc3JjPSJodHRwczovL3MwLndwLmNvbS93cC1jb250ZW50L211LXBsdWdpbnMvd3Bjb20tc21pbGV5cy90d2Vtb2ppLzIvNzJ4NzIvMWZhYzYucG5nIiBhbHQ9IvCfq4YiIGNsYXNzPSJ3cC1zbWlsZXkiIHN0eWxlPSJoZWlnaHQ6IDFlbTsgbWF4LWhlaWdodDogMWVtOyIgLz4sIFNQTEFUVEVSIDxpbWcgc3JjPSJodHRwczovL3MwLndwLmNvbS93cC1jb250ZW50L211LXBsdWdpbnMvd3Bjb20tc21pbGV5cy90d2Vtb2ppLzIvNzJ4NzIvMWZhZGYucG5nIiBhbHQ9IvCfq58iIGNsYXNzPSJ3cC1zbWlsZXkiIHN0eWxlPSJoZWlnaHQ6IDFlbTsgbWF4LWhlaWdodDogMWVtOyIgLz4sIEhBUlAgPGltZyBzcmM9Imh0dHBzOi8vczAud3AuY29tL3dwLWNvbnRlbnQvbXUtcGx1Z2lucy93cGNvbS1zbWlsZXlzL3R3ZW1vamkvMi83Mng3Mi8xZmE4OS5wbmciIGFsdD0i8J+qiSIgY2xhc3M9IndwLXNtaWxleSIgc3R5bGU9ImhlaWdodDogMWVtOyBtYXgtaGVpZ2h0OiAxZW07IiAvPi4gVGhpcyBtZWFucyB0aGF0IGFsbCBvZiB0aGUgY2hhbmdlcyBvZiA8YSBocmVmPSJodHRwczovL3d3dy51bmljb2RlLm9yZy92ZXJzaW9ucy9Vbmljb2RlMTYuMC4wLyI+VW5pY29kZSAxNjwvYT4gYW5kIDxhIGhyZWY9Imh0dHBzOi8vd3d3LnVuaWNvZGUub3JnL3ZlcnNpb25zL1VuaWNvZGUxNy4wLjAvIj5Vbmljb2RlIDE3PC9hPiB3ZXJlIGltcGxlbWVudGVkIHRvIGEgdmVyeSBoaWdoIGRlZ3JlZS4gUXVpdGUgYSBmZWF0ITwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+PGVtPlBhdHJpY2sgQsO2a2VyPC9lbT4gd2FzIDxzdHJvbmc+cmVhbGx5PC9zdHJvbmc+IGJ1c3kgdGhpcyB5ZWFyOiBuZXcgc2NyaXB0IHJ1bm5lcnMgbm90IG9ubHkgbWFkZSBleGVjdXRpb24gb2YgQ0xJLXNjcmlwdHMgYSBiaXQgZmFzdGVyLCBpdCBhbHNvIG1hZGUgaXQgcG9zc2libGUgdG8gcnVuIENMSS1zY3JpcHRzIG9uIFdpbmRvd3Mgd2l0aG91dCBhbnkgaXNzdWVzLjwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+QWdhaW4sIGEgbG90IG9mIHdvcmsgd2FzIGRvbmUgb24gbWFraW5nIHRoZSBDb250aW51b3VzIEludGVncmF0aW9uIHRlc3RpbmcgcHJvZHVjZSBmZXdlciAoYW5kIHJlY2VudGx5IGhhcmRseSBhbnkpIGZhbHNlIHBvc2l0aXZlcyBhbnltb3JlLiBXaGljaCBtYWtlcyBsaWZlIGZvciBjb3JlIGRldmVsb3BlcnMgYSA8ZW0+bG90PC9lbT4gZWFzaWVyITwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VmVyeSBpbXBvcnRhbnQgZm9yIHBhY2thZ2VyczogUmFrdWRvIG5vdyBhZ2FpbiBoYXMgYSByZXByb2R1Y2libGUgYnVpbGQgcHJvY2VzcywgdGhhbmtzIGZvciA8ZW0+VGltbyBQYXVsc3NlbjwvZW0+IGFuZCBvdGhlcnMuPC9wPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5BbHNvIHRoZSBSRVBMIChSZWFkLCBFdmFsdWF0ZSwgUHJpbnQgTG9vcCkgaGFzIGJlZW4gaW1wcm92ZWQ6IGdyYW1tYXIgY2hhbmdlcyBhcmUgbm93IHBlcnNpc3RlbnQsIGFuZCBpdCYjODIxNztzIGFsc28gcG9zc2libGUgdG8gZW50ZXIgbXVsdGktbGluZSBjb21tZW50cy4gIFNvbWUgb2YgdGhlc2UgY2hhbmdlcyB3ZXJlIGJhY2twb3J0ZWQgZnJvbSB0aGUgPGNvZGU+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOmxpem1hdC9SRVBMIj5SRVBMPC9hPjwvY29kZT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6bGl6bWF0L1JFUEwiPiBtb2R1bGU8L2E+LCBhcyBkZXNjcmliZWQgaW4gdGhpcyA8YSBocmVmPSJodHRwczovL2Rldi50by9saXptYXQvcmVwbC1hdmFsYW5jaGUtNDVoaCI+YmxvZyBwb3N0PC9hPi48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRoZSB0ZXN0cyBmb3IgZXhwZXJpbWVudGFsIFJha3UgZmVhdHVyZXMgKHN1Y2ggYXMgPGNvZGU+PGEgaHJlZj0iaHR0cHM6Ly9kb2NzLnJha3Uub3JnL2xhbmd1YWdlL2V4cGVyaW1lbnRhbCNwYWNrIj46cGFjazwvYT48L2NvZGU+LCA8Y29kZT48YSBocmVmPSJodHRwczovL2RvY3MucmFrdS5vcmcvbGFuZ3VhZ2UvZXhwZXJpbWVudGFsI2NhY2hlZCI+OmNhY2hlZDwvYT48L2NvZGU+LCA8Y29kZT48YSBocmVmPSJodHRwczovL2RvY3MucmFrdS5vcmcvbGFuZ3VhZ2UvZXhwZXJpbWVudGFsI21hY3JvcyI+Om1hY3JvczwvYT48L2NvZGU+KSBoYXZlIGJlZW4gbW92ZWQgZnJvbSB0aGUgUmFrdSB0ZXN0LXN1aXRlIChyb2FzdCkgdG8gdGhlIFJha3VkbyByZXBvc2l0b3J5LCBhcyB0aGV5IGFyZSB0ZWNobmljYWxseSBub3QgcGFydCBvZiB0aGUgZGVmaW5pdGlvbiBvZiB0aGUgUmFrdSBQcm9ncmFtbWluZyBMYW5ndWFnZS48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlNhZGx5LCB0aGUgSlZNIGJhY2tlbmQgaGFzIGhhcmRseSBzZWVuIGFueSB1cGRhdGVzIHRoZSBwYXN0IHllYXIuICBJdCB3YXMgdGhlcmVmb3JlIGRlY2lkZWQgdG8gbm90IG1lbnRpb24gdGhlIEpWTSBiYWNrZW5kIGluIHJlbGVhc2VzIGFueW1vcmUsIG5vciB0byBtYWtlIHN1cmUgdGhhdCB0aGVyZSB3b3VsZCBub3QgYmUgYW55IGVjb3N5c3RlbSBicmVha2FnZSBvbiB0aGUgSlZNIGJhY2tlbmQgYmVmb3JlIGEgcmVsZWFzZS48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPklmIHlvdSB3YW50IHRoZSBKVk0gdG8gcmVtYWluIGEgdmlhYmxlIGJhY2tlbmQsIHlvdSBhcmUgdmVyeSBtdWNoIGludml0ZWQgdG8gZ2V0IGludm9sdmVkITwvcD4KCgoKPGgzIGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5OZXcgZmVhdHVyZXMgaW4gNi5kPC9oMz4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIG1vc3Qgbm90YWJsZSBuZXcgZmVhdHVyZXMgaW4gdGhlIGRlZmF1bHQgbGFuZ3VhZ2UgbGV2ZWw6PC9wPgoKCgo8aDQgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPlZhcmFyZ3Mgc3VwcG9ydCBpbiA8Y29kZT5OYXRpdmVDYWxsPC9jb2RlPjwvaDQ+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkFmdGVyIG1hbnkgeWVhcnMgb2YgcGVvcGxlIGFza2luZyBmb3IgdGhpcyBmZWF0dXJlLCA8ZW0+UGF0cmljayBCw7ZrZXI8L2VtPiBhY3R1YWxseSB3cm90ZSB0aGUgaW5mcmFzdHJ1Y3R1cmUgaW4gPGNvZGU+TW9hclZNPC9jb2RlPiBhbmQgPGNvZGU+UmFrdWRvPC9jb2RlPiB0byBzdXBwb3J0IGNhbGxpbmcgPGNvZGU+QzwvY29kZT4tZnVuY3Rpb25zIHRoYXQgc3VwcG9ydCBhIHZhcmlhYmxlIG51bWJlciBvZiBhcmd1bWVudHMgdXNpbmcgdGhlIDxhIGhyZWY9Imh0dHBzOi8vbGludXguZGllLm5ldC9tYW4vMy92YV9hcmciPjxjb2RlPnZhX2FyZzwvY29kZT4gc3RhbmRhcmQ8L2E+LjwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VG8gZ2l2ZSBhbiBleGFtcGxlLCBpdCYjODIxNztzIG5vdyBwb3NzaWJsZSB0byBjcmVhdGUgYSA8Y29kZT5mb288L2NvZGU+IHN1YnJvdXRpbmUgdGhhdCB3aWxsIGNhbGwgdGhlIDxjb2RlPnByaW50ZjwvY29kZT4gQy1mdW5jdGlvbiAoZnJvbSB0aGUgc3RhbmRhcmQgbGlicmFyeSkgdGhhdCB0YWtlcyBhIGZvcm1hdCBzdHJpbmcgYXMgdGhlIGZpcnN0IGFyZ3VtZW50LCBhbmQgYSB2YXJpYWJsZSBudW1iZXIgb2YgYXJndW1lbnRzIGFmdGVyIHRoYXQ6PC9wPgoKCgo8cHJlIGNsYXNzPSJ3cC1ibG9jay1jb2RlIGhhcy1mb3JlZ3JvdW5kLWJhY2tncm91bmQtY29sb3IgaGFzLWJhY2tncm91bmQgaGFzLXNtYWxsLWZvbnQtc2l6ZSIgc3R5bGU9ImJvcmRlci13aWR0aDo4cHgiPjxjb2RlPnVzZSBOYXRpdmVDYWxsOwpzdWIgZm9vKDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzZjZTQyNyIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPnN0ciwgKipAIC0tJmd0OyBpbnQzMjwvbWFyaz4pIGlzIG5hdGl2ZSBpcyBzeW1ib2woJ3ByaW50ZicpIHsqfQpmb28gIlRoZSBhbnN3ZXI6ICVkXG4iLCA0MjsgICMgVGhlIGFuc3dlcjogNDI8L2NvZGU+PC9wcmU+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRoZSA8Y29kZT5wcmludGYoKTwvY29kZT4gPGNvZGU+QzwvY29kZT4tZnVuY3Rpb24gaXMgYSBnb29kIGV4YW1wbGUgb2YgdXNpbmcgdmFyYXJncy4gIDwvcD4KCgoKPGg0IGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5TdXBwb3J0IGZvciBwc2V1ZG8tdGVybWluYWxzIChQVFkpPC9oND4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+V3JpdGluZyB0ZXJtaW5hbCBhcHBsaWNhdGlvbnMgaGFzIGJlY29tZSBtdWNoIHNpbXBsZXIgd2l0aCB0aGUgc3VwcG9ydCBmb3IgcHNldWRvLXRlcm1pbmFscyB0aGF0IDxlbT5QYXRyaWNrIELDtmtlcjwvZW0+IGhhcyB3cml0dGVuLiAgVGhpcyA8YSBocmVmPSJodHRwczovL3Jha3UtYWR2ZW50LmJsb2cvMjAyNS8xMi8yMS9hLXRlcm1pbmFscy10YWxlLyI+QWR2ZW50IHBvc3Q8L2E+IGV4cGxhaW5zIHRoZSBob3cgYW5kIHdoeSBvZiB0aGlzIGRldmVsb3BtZW50LCBhbmQgdGhlIG5ldyA8YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6cGF0cmlja2IvQW5vbGlzIj48Y29kZT5Bbm9saXM8L2NvZGU+IHRlcm1pbmFsIGVtdWxhdG9yIG1vZHVsZTwvYT4uPC9wPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5TdXBwb3J0IGlzIHN0aWxsIGEgYml0IHJhdyBhcm91bmQgdGhlIGVkZ2VzOiBwcmV0dHkgc3VyZSB0aGUgY29taW5nIHllYXIgd2lsbCBzZWUgYSBsb3Qgb2Ygc21vb3RoaW5nIG92ZXIsIHNvIHRoYXQgaXQgY2FuIGUuZy4gYmUgdXNlZCB0byBjcmVhdGUgYSBmdWxsIGZlYXR1cmVkIHRlcm1pbmFsLWJhc2VkIFJha3UgZGVidWdnZXIhPC9wPgoKCgo8aDQgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPjxjb2RlPkhhc2gubmV3KGEgPSZndDsgNDIsIGIgPSZndDsgNjY2KTwvY29kZT48L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5BIGNvbW1vbiBiZWdpbm5lciBtaXN0YWtlIHdhcyB0cnlpbmcgdG8gY3JlYXRlIGEgbmV3IDxjb2RlPkhhc2g8L2NvZGU+IChvciA8Y29kZT5NYXA8L2NvZGU+KSBvYmplY3QgYnkgdXNpbmcgPGNvZGU+Lm5ldzwvY29kZT4gYW5kIG5hbWVkIGFyZ3VtZW50cy4gVGhpcyB3b3VsZCBzaWxlbnRseSBjcmVhdGUgYW4gZW1wdHkgPGNvZGU+SGFzaDwvY29kZT4gKG9yIDxjb2RlPk1hcDwvY29kZT4pIGJlY2F1c2UgYnkgZGVmYXVsdCBhbnkgdW5leHBlY3RlZCBuYW1lZCBhcmd1bWVudHMgYXJlIGlnbm9yZWQgaW4gY2FsbHMgdG8gPGNvZGU+Lm5ldzwvY29kZT4uIFRoaXMgd2FzIGNoYW5nZWQgc28gdGhhdCBpZiA8Y29kZT5IYXNoLm5ldzwvY29kZT4gKG9yIDxjb2RlPk1hcC5uZXc8L2NvZGU+KSBpcyBjYWxsZWQgd2l0aCBuYW1lZCBhcmd1bWVudHMgb25seSwgdGhleSB3aWxsIGJlIGludGVycHJldGVkIGFzIGtleS92YWx1ZSBwYWlycyB0byBiZSBwdXQgaW50byB0aGUgPGNvZGU+SGFzaDwvY29kZT4gKG9yIDxjb2RlPk1hcDwvY29kZT4pOjwvcD4KCgoKPHByZSBjbGFzcz0id3AtYmxvY2stY29kZSBoYXMtZm9yZWdyb3VuZC1iYWNrZ3JvdW5kLWNvbG9yIGhhcy1iYWNrZ3JvdW5kIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjhweCI+PGNvZGU+ZGQgSGFzaC5uZXcoPG1hcmsgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6cmdiYSgwLCAwLCAwLCAwKTtjb2xvcjojNmNlNDI3IiBjbGFzcz0iaGFzLWlubGluZS1jb2xvciI+YSA9Jmd0OyA0MiwgYiA9Jmd0OyA2NjYpPC9tYXJrPjsKIyB7OmEoNDIpLCA6Yig2NjYpfQpkZCBNYXAubmV3KDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzZjZTQyNyIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPmEgPSZndDsgNDIsIGIgPSZndDsgNjY2KTwvbWFyaz47CiMgTWFwLm5ldygoOmEoNDIpLDpiKDY2NikpKTwvY29kZT48L3ByZT4KCgoKPGg0IGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5leGl0LW9rPC9oND4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIDxjb2RlPlRlc3Q8L2NvZGU+IG1vZHVsZSBub3cgYWxzbyBwcm92aWRlcyBhbiA8Y29kZT5leGl0LW9rPC9jb2RlPiB0ZXN0ZXIgc3Vicm91dGluZSwgbWFraW5nIGl0IGEgbG90IGVhc2llciB0byB0ZXN0IHRoZSBleGl0IGJlaGF2aW91ciBvZiBhIHBpZWNlIG9mIGNvZGUuICBJdCB0YWtlcyBhIDxjb2RlPkNhbGxhYmxlPC9jb2RlPiwgYW5kIGFuIGludGVnZXIgdmFsdWUuICBJdCBleHBlY3RzIHRoZSBjb2RlIHRvIGV4ZWN1dGUgYW4gPGEgaHJlZj0iaHR0cHM6Ly9kb2NzLnJha3Uub3JnL3JvdXRpbmUvZXhpdCI+PGNvZGU+ZXhpdDwvY29kZT4gc3RhdGVtZW50PC9hPiwgYW5kIHdpbGwgdGhlbiBjb21wYXJlIHRoZSAoaW1wbGljaXRseSkgZ2l2ZW4gZXhpdCB2YWx1ZSB3aXRoIHRoZSBnaXZlbiBpbnRlZ2VyIHZhbHVlLjwvcD4KCgoKPHByZSBjbGFzcz0id3AtYmxvY2stY29kZSBoYXMtZm9yZWdyb3VuZC1iYWNrZ3JvdW5kLWNvbG9yIGhhcy1iYWNrZ3JvdW5kIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjhweCI+PGNvZGU+dXNlIFRlc3Q7CjxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzZjZTQyNyIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPmV4aXQtb2sgeyBleGl0IDEgfSwgMTwvbWFyaz47CiMgb2sgMSAtIFdhcyB0aGUgZXhpdCBjb2RlIDE/CjxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzZjZTQyNyIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPmV4aXQtb2sgeyBleGl0IH0sIDE8L21hcms+OwojIG5vdCBvayAyIC0gV2FzIHRoZSBleGl0IGNvZGUgMT8KPG1hcmsgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6cmdiYSgwLCAwLCAwLCAwKTtjb2xvcjojNmNlNDI3IiBjbGFzcz0iaGFzLWlubGluZS1jb2xvciI+ZXhpdC1vayB7IDQyIH0sIDA8L21hcms+OwojIG5vdCBvayAzIC0gQ29kZSBkaWQgbm90IGV4aXQsIG5vIGV4aXQgdmFsdWUgdG8gY2hlY2s8L2NvZGU+PC9wcmU+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+TGFuZ3VhZ2UgY2hhbmdlcyAoNi5lLlBSRVZJRVcpPC9oND4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIG1vc3Qgbm90YWJsZSBhZGRpdGlvbnMgdG8gdGhlIGZ1dHVyZSBsYW5ndWFnZSBsZXZlbCBvZiB0aGUgUmFrdSBQcm9ncmFtbWluZyBMYW5ndWFnZTo8L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+SGFzaDo6T3JkZXJlZDwvaDQ+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkFuIGltcGxlbWVudGF0aW9uIG9mIG9yZGVyZWQgaGFzaGVzIChhIGhhc2ggaW4gd2hpY2ggdGhlIG9yZGVyIG9mIHRoZSBrZXlzIGlzIGRldGVybWluZWQgYnkgb3JkZXIgb2YgYWRkaXRpb24pIGhhcyBiZWNvbWUgYXZhaWxhYmxlOjwvcD4KCgoKPHByZSBjbGFzcz0id3AtYmxvY2stY29kZSBoYXMtZm9yZWdyb3VuZC1iYWNrZ3JvdW5kLWNvbG9yIGhhcy1iYWNrZ3JvdW5kIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjhweCI+PGNvZGU+dXNlIHY2LmUuUFJFVklFVzsKbXkgJWggPG1hcmsgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6cmdiYSgwLCAwLCAwLCAwKTtjb2xvcjojNDhlMTI0IiBjbGFzcz0iaGFzLWlubGluZS1jb2xvciI+PHN0cm9uZz5pcyBIYXNoOjpPcmRlcmVkPC9zdHJvbmc+PC9tYXJrPiA9ICJhIi4uImUiIFo9Jmd0OyAxLi41OwpzYXkgJWgua2V5czsgICAgIyAmIzA5MTthIGIgYyBkIGVdCnNheSAlaC52YWx1ZXM7ICAjICgxIDIgMyA0IDUpPC9jb2RlPjwvcHJlPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5UaGlzIHdpbGwgcHJvYmFibHkgZ2V0IHNvbWUgZWFzaWVyIHN5bnRhY3RpYyBzdWdhci4gIFVudGlsIHRoZW4sIHRoZSBhYm92ZSBzeW50YXggY2FuIGJlIHVzZWQuPC9wPgoKCgo8aDMgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPkxhbmd1YWdlIGNoYW5nZXMgaW4gUmFrdUFTVDwvaDM+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRoZSBmb2xsb3dpbmcgY2hhbmdlcyBhcmUgb25seSBzZWVuIHdoZW4gdXNpbmcgPGNvZGU+UmFrdUFTVDwvY29kZT4gKGJ5IGNhbGxpbmcgPGNvZGU+cmFrdTwvY29kZT4gd2l0aCB0aGUgPGNvZGU+UkFLVURPX1JBS1VBU1Q9MTwvY29kZT4gZW52aXJvbm1lbnQgdmFyaWFibGUgc2V0KSwgYW5kIHRodXMgYXZhaWxhYmxlIGJ5IGRlZmF1bHQgd2hlbiB0aGUgbmV4dCBsYW5ndWFnZSBsZXZlbCBpcyByZWxlYXNlZC48L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+U2V0dGluZyBkZWZhdWx0IGxhbmd1YWdlIHZlcnNpb248L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5UaGUgPGNvZGU+UkFLVV9MQU5HVUFHRV9WRVJTSU9OPC9jb2RlPiBlbnZpcm9ubWVudCB2YXJpYWJsZSBjYW4gYmUgdXNlZCB0byBpbmRpY2F0ZSB0aGUgZGVmYXVsdCBsYW5ndWFnZSBsZXZlbCB3aXRoIHdoaWNoIHRvIGNvbXBpbGUgYW55IFJha3Ugc291cmNlIGNvZGUuICBOb3RlIHRoYXQgdGhpcyBkb2VzIDxzdHJvbmc+bm90PC9zdHJvbmc+IGFmZmVjdCBhbnkgZXhwbGljaXQgbGFuZ3VhZ2UgdmVyc2lvbnMgc3BlY2lmaWVkIGluIHRoZSBjb2RlLjwvcD4KCgoKPHByZSBjbGFzcz0id3AtYmxvY2stY29kZSBoYXMtZm9yZWdyb3VuZC1iYWNrZ3JvdW5kLWNvbG9yIGhhcy1iYWNrZ3JvdW5kIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjhweDtmb250LXNpemU6MTRweCI+PGNvZGU+JCBSQUtVRE9fUkFLVUFTVD0xIDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzQzZDcxZiIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPjxzdHJvbmc+UkFLVV9MQU5HVUFHRV9WRVJTSU9OPTYuZS5QUkVWSUVXPC9zdHJvbmc+PC9tYXJrPiByYWt1IC1lICdzYXkgbmFubycKMTc2NjQzMDE0NTQxODgyMTY3MAokIFJBS1VET19SQUtVQVNUPTEgPG1hcmsgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6cmdiYSgwLCAwLCAwLCAwKTtjb2xvcjojNDNkNzFmIiBjbGFzcz0iaGFzLWlubGluZS1jb2xvciI+PHN0cm9uZz5SQUtVX0xBTkdVQUdFX1ZFUlNJT049Ni5lLlBSRVZJRVc8L3N0cm9uZz48L21hcms+IHJha3UgLWUgJ3VzZSB2Ni5kOyBzYXkgbmFubycKPT09U09SUlkhPT09IEVycm9yIHdoaWxlIGNvbXBpbGluZyAtZQpVbmRlY2xhcmVkIHJvdXRpbmU6CiAgICBuYW5vIHVzZWQgYXQgbGluZSAxPC9jb2RlPjwvcHJlPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5BbHRob3VnaCBvZiBsaW1pdGVkIHVzZSB3aGlsZSBSYWt1QVNUIGlzIG5vdCB5ZXQgdGhlIGRlZmF1bHQsIGl0IDxzdHJvbmc+d2lsbDwvc3Ryb25nPiBtYWtlIGl0IGEgbG90IGVhc2llciB0byBjaGVjayB0aGUgYmVoYXZpb3VyIG9mIGNvZGUgYXQgZGlmZmVyZW50IGxhbmd1YWdlIGxldmVscywgZS5nLiB3aGVuIHJ1bm5pbmcgdGVzdHMgaW4gdGhlIG9mZmljaWFsIHRlc3Qtc3VpdGUgKGFrYSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vcmFrdS9yb2FzdD90YWI9cmVhZG1lLW92LWZpbGUjdGhlLW9mZmljaWFsLXJha3UtdGVzdC1zdWl0ZSI+cm9hc3Q8L2E+KS48L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+PGNvZGU+JD9TT1VSQ0UsICQ/Q0hFQ0tTVU08L2NvZGU+PC9oND4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIGNvbXBpbGUtdGltZSB2YXJpYWJsZXMgPGNvZGU+JD9TT1VSQ0U8L2NvZGU+IGFuZCA8Y29kZT4kP0NIRUNLU1VNPC9jb2RlPiBoYXZlIGJlZW4gYWRkZWQuICBUaGUgPGNvZGU+JD9TT1VSQ0U8L2NvZGU+IGNvbXBpbGUtdGltZSB2YXJpYWJsZSBjb250YWlucyB0aGUgc291cmNlIG9mIHRoZSBjdXJyZW50IGNvbXBpbGF0aW9uIHVuaXQuICBJZiBmb3Igc29tZSByZWFzb24gb25lIGRvZXNuJiM4MjE3O3Qgd2FudCB0aGF0IHRvIGJlIGluY2x1ZGVkIGluIHRoZSBieXRlY29kZSwgdGhlbiB0aGUgPGNvZGU+UkFLVURPX09NSVRfU09VUkNFPC9jb2RlPiBlbnZpcm9ubWVudCB2YXJpYWJsZSBjYW4gYmUgc2V0LjwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIDxjb2RlPiQ/Q0hFQ0tTVU08L2NvZGU+IGNvbXBpbGUtdGltZSB2YXJpYWJsZSBjb250YWlucyBhIDxjb2RlPlNIQTE8L2NvZGU+IGRpZ2VzdCBvZiB0aGUgc291cmNlIGNvZGUuPC9wPgoKCgo8cHJlIGNsYXNzPSJ3cC1ibG9jay1jb2RlIGhhcy1mb3JlZ3JvdW5kLWJhY2tncm91bmQtY29sb3IgaGFzLWJhY2tncm91bmQiIHN0eWxlPSJib3JkZXItd2lkdGg6OHB4Ij48Y29kZT4kIFJBS1VET19SQUtVQVNUPTEgcmFrdSAtZSAnc2F5IDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzRhZWExYiIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPjxzdHJvbmc+JD9TT1VSQ0U8L3N0cm9uZz48L21hcms+JwpzYXkgJD9TT1VSQ0UKJCBSQUtVRE9fUkFLVUFTVD0xIHJha3UgLWUgJ3NheSA8bWFyayBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsIDAsIDAsIDApO2NvbG9yOiM0YWVhMWIiIGNsYXNzPSJoYXMtaW5saW5lLWNvbG9yIj48c3Ryb25nPiQ/Q0hFQ0tTVU08L3N0cm9uZz48L21hcms+Jwo4MTg5MkJBMzhCOUJENjkzMDM4MEJEODFEQjk0OEU0RDdBOUMxNEU3CiQgUkFLVURPX1JBS1VBU1Q9MSA8bWFyayBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsIDAsIDAsIDApO2NvbG9yOiM0YWVhMWIiIGNsYXNzPSJoYXMtaW5saW5lLWNvbG9yIj5SQUtVRE9fT01JVF9TT1VSQ0U9MTwvbWFyaz4gcmFrdSAtZSAnc2F5IDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzRhZWExYiIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPjxzdHJvbmc+JD9TT1VSQ0U8L3N0cm9uZz48L21hcms+JwpOaWw8L2NvZGU+PC9wcmU+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRoZXNlIGFkZGl0aW9ucyBhcmUgaW50ZW5kZWQgdG8gYmUgdXNlZCBieSB0aGUgPGNvZGU+TW9hclZNPC9jb2RlPiBydW50aW1lIGRlYnVnZ2VyLCBhcyB3ZWxsIGFzIGJ5IHBhY2thZ2VycyBmb3IgdmVyaWZpY2F0aW9uLjwvcD4KCgoKPGg0IGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5Mb2NhbGl6YXRpb248L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5Nb3N0IG9mIHRoZSBsb2NhbGl6YXRpb24gd29yayBoYXMgYmVlbiByZW1vdmVkIGZyb20gdGhlIFJha3VkbyBjb3JlIGFuZCBwdXQgaW50byBzZXBhcmF0ZSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vcmFrdS1MMTBOIj5SYWt1LUwxME4gcHJvamVjdDwvYT4uICBBbmQgdGhlcmUgaXQgZ2FpbmVkIGEgZmV3IG5ldyBjb250cmlidXRvcnMhICBGb3IgYSBwcm9ncmVzcyByZXBvcnQsIGNoZWNrb3V0IG91dCA8ZW0+aGFiZXJlLWV0LWRpcGVydGlyZTwvZW0+JiM4MjE2O3MgYWR2ZW50IGJsb2cgcG9zdCB0aXRsZWQgPGEgaHJlZj0iaHR0cHM6Ly9yYWt1LWFkdmVudC5ibG9nLzIwMjUvMTIvMTgvZGF5LTE4LWhhbGxvLXdlcmVsZC8iPkhhbGxvLCBXw6pyZWxkITwvYT48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRvIG1ha2UgaXQgZWFzaWVyIHRvIHdvcmsgd2l0aCBjb2RlIGluIGEgc3BlY2lmaWMgbG9jYWxpemF0aW9uLCBlYWNoIGxvY2FsaXphdGlvbiBjb21lcyB3aXRoIGEgJiM4MjIwO2Z1biYjODIyMTsgY29tbWFuZCBsaW5lIHNjcmlwdCwgYW5kIGFuIG9mZmljaWFsIG9uZS4gIFNvIGZvciBpbnN0YW5jZSwgdGhlIDxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpsMTBuL0wxME46Ok5MIj5EdXRjaCBsb2NhbGl6YXRpb248L2E+IGhhcyBhICYjODIyMDtkdXRrdSYjODIyMTsgKGZvciA8c3Ryb25nPmR1dDwvc3Ryb25nPmNoIHJhPHN0cm9uZz5rdTwvc3Ryb25nPikgZXhlY3V0YWJsZSAod2VsbCwgYWN0dWFsbHkgYSBDTEkgc2NyaXB0KSwgYnV0IGFsc28gYSAmIzgyMjA7a2FhcyYjODIyMTsgb25lLiAgU2FtZSBmb3IgRnJlbmNoICgmIzgyMjA7ZnJla3UmIzgyMjE7IGFuZCAmIzgyMjA7YnJpZSYjODIyMTspLCBldGMuICBUaGUgZnVuIG9uZSBpcyB1c3VhbGx5IGFzc29jaWF0ZWQgd2l0aCBhIGZhdm91cml0ZSBmb29kc3R1ZmYgb2YgdGhlIGxhbmd1YWdlIGluIHF1ZXN0aW9uLjwvcD4KCgoKPHByZSBjbGFzcz0id3AtYmxvY2stY29kZSBoYXMtZm9yZWdyb3VuZC1iYWNrZ3JvdW5kLWNvbG9yIGhhcy1iYWNrZ3JvdW5kIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjhweCI+PGNvZGU+JCA8bWFyayBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsIDAsIDAsIDApO2NvbG9yOiM0YWVhMWIiIGNsYXNzPSJoYXMtaW5saW5lLWNvbG9yIj48c3Ryb25nPmR1dGt1PC9zdHJvbmc+PC9tYXJrPiAtZSAnemVnICJmb28iJwpmb28KJCA8bWFyayBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsIDAsIDAsIDApO2NvbG9yOiM0YWVhMWIiIGNsYXNzPSJoYXMtaW5saW5lLWNvbG9yIj48c3Ryb25nPmthYXM8L3N0cm9uZz48L21hcms+IC1lICd6ZWcgImZvbyInCmZvbwokIDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzRhZWExYiIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPjxzdHJvbmc+ZnJla3U8L3N0cm9uZz48L21hcms+IC1lICdkaXMgImZvbyInCmZvbwokIDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzRhZWExYiIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPjxzdHJvbmc+YnJpZTwvc3Ryb25nPjwvbWFyaz4gLWUgJ2RpcyAiZm9vIicKZm9vPC9jb2RlPjwvcHJlPgoKCgo8aDQgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPlJha3VEb2M8L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5UaGUgUmFrdURvYyB2Mi4wIHNwZWNpZmljYXRpb24gd2FzIGNvbXBsZXRlZCBpbiBEZWNlbWJlciAyMDI0LCBhbmQgMjAyNSB3YXMgc3BlbnQgaW1wbGVtZW50aW5nIGl0LiBBIGNvbXBsaWFudCByZW5kZXJlciBpcyBub3cgYXZhaWxhYmxlIGJ5IGluc3RhbGxpbmcgdGhlIDxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpmaW5hbmFseXN0L1Jha3Vhc3Q6OlJha3VEb2M6OlJlbmRlciI+UmFrdWFzdDo6UmFrdURvYzo6UmVuZGVyPC9hPiBkaXN0cmlidXRpb24uIFdvcmsgdGhlbiBiZWdhbiBvbiBhIGRvY3VtZW50IG1hbmFnZW1lbnQgc3lzdGVtIGNhbGxlZCA8YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6ZmluYW5hbHlzdC9FbHVjaWQ4OjpCdWlsZCI+RWx1Y2lkODwvYT4gd2hpY2ggcmVuZGVycyB0aGUgd2hvbGUgUmFrdSBkb2N1bWVudGF0aW9uICg8YSBocmVmPSJodHRwczovL2Rldi5kb2NzLnJha3Uub3JnIj5kZXZlbG9wbWVudCBwcmV2aWV3PC9hPikuPGJyPjxicj5Gcm9tIFNlcHRlbWJlciBvbndhcmRzLCA8ZW0+RGFtaWFuIENvbndheTwvZW0+IGFuZCA8ZW0+UmljaGFyZCBIYWluc3dvcnRoPC9lbT4gd29ya2VkIG9uIGEgZW51bWVyYXRpb24gc3lzdGVtIChvcmlnaW5hbGx5IGVudmlzaW9uZWQgZm9yIFJha3VEb2MgdjMuMCkgc28gdGhhdCBhbnkgYmxvY2sgJiM4MjExOyBtZWFuaW5nIGFueSBwYXJhZ3JhcGgsIGhlYWRpbmcsIGNvZGUgc25pcHBldCwgZm9ybXVsYSwgZXRjICYjODIxMTsgY2FuIGJlIGVudW1lcmF0ZWQgc2ltcGx5IGJ5IHByZWZpeGluZyB0aGUgYmxvY2t0eXBlIHdpdGggPGNvZGU+bnVtPC9jb2RlPi4gSXQgaXMgYSBmYXIgbW9yZSBmbGV4aWJsZSBzeXN0ZW0gdGhhbiBhbnl0aGluZyBlbmNvdW50ZXJlZCBpbiB0aGUgZWRpdG9yIHNwYWNlLjwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIFJha3VEb2Mgc3BlY2lmaWNhdGlvbiBpcyBub3cgYXQgPGEgaHJlZj0iaHR0cHM6Ly9odG1scHJldmlldy5naXRodWIuaW8vP2h0dHBzOi8vZ2l0aHViLmNvbS9SYWt1L1Jha3VEb2MtR0FNTUEvYmxvYi9udW1hbGlhcy1jbGFyaWZpY2F0aW9uL3Jha3Vkb2NfdjIuaHRtbCI+dmVyc2lvbiAyLjIwLjI8L2E+LiAgVGhlIG5ldyBlbnVtZXJhdGlvbiBzcGVjaWZpY2F0aW9uIGhhcyBub3QgeWV0IGJlZW4gbWVyZ2VkIHRvIG1haW4gYmVjYXVzZSB3b3JrIGlzIHN0aWxsIGJlaW5nIGRvbmUgb24gZ2V0dGluZyA8Y29kZT5SYWt1YXN0OjpSYWt1RG9jOjpSZW5kZXI8L2NvZGU+IHRvIGltcGxlbWVudCB0aGUgbmV3IHN0YW5kYXJkLjwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+SXQgcmVhbGx5IGxvb2tzIGxpa2UgUmFrdURvYyBoYXMgdGhlIHBvdGVudGlhbCB0byBiZWNvbWluZyA8c3Ryb25nPnRoZTwvc3Ryb25nPiBtYXJrdXAgbGFuZ3VhZ2UgZm9yIGFueSB0eXBlIG9mIHNlcmlvdXMgZG9jdW1lbnRhdGlvbiwgYW5kIGEgZGlyZWN0IGNvbXBldGl0b3IgdG8gbWFya2Rvd24uPC9wPgoKCgo8aDMgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPkVjb3N5c3RlbTwvaDM+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRoZSA8YSBocmVmPSJodHRwczovL3Jha3UubGFuZCI+UmFrdSBlY29zeXN0ZW08L2E+IGhhcyBzZWVuIHF1aXRlIGEgbG90IG9mIGRldmVsb3BtZW50cy4gIE1hbnkgbW9kdWxlcyBnb3QgbW92ZWQgdG8gdGhlIDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9yYWt1LWNvbW11bml0eS1tb2R1bGVzIj5SYWt1IENvbW11bml0eSBNb2R1bGVzIEFkb3B0aW9uIENlbnRlcjwvYT4gd2hlcmUgdGhleSBnb3QgYSA8YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6cmFrdS1jb21tdW5pdHktbW9kdWxlcyI+bmV3IGxlYXNlIG9uIGxpZmU8L2E+LiAgQnV0IHRoZXJlIHdlcmUgYWxzbyBxdWl0ZSBhIGZldyBuZXcgbW9kdWxlcywgYW5kIGludGVyZXN0aW5nIHVwZGF0ZXMgdG8gZXhpc3RpbmcgbW9kdWxlcyBpbiAyMDI1LjwvcD4KCgoKPGg0IGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5TdGF0aXN0aWNzPC9oND4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+QWNjb3JkaW5nIHRvIDxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3N0YXRzIj5yYWt1LmxhbmQ8L2E+IGluIDIwMjUsIDxlbT41MDM8L2VtPiBSYWt1IG1vZHVsZXMgaGF2ZSBiZWVuIHVwZGF0ZWQgKG9yIGZpcnN0IHJlbGVhc2VkKTogdXAgZnJvbSA8ZW0+MzY3PC9lbT4gaW4gMjAyNCAoYW4gaW5jcmVhc2Ugb2YgMzclKS4gVGhlcmUgYXJlIG5vdyA8ZW0+MjQzMTwvZW0+IGRpZmZlcmVudCBtb2R1bGVzIGluc3RhbGxhYmxlIGJ5IDxjb2RlPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjp1Z2V4ZS96ZWYiPnplZjwvYT48L2NvZGU+IGJ5IGp1c3QgbWVudGlvbmluZyB0aGVpciBuYW1lLiBBbmQgdGhlcmUgYXJlIG5vdyA8ZW0+MTM4MDg8L2VtPiBkaWZmZXJlbnQgdmVyc2lvbnMgb2YgUmFrdSBtb2R1bGVzIGF2YWlsYWJsZSBmcm9tIHRoZSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vcmFrdS9SRUE/dGFiPXJlYWRtZS1vdi1maWxlI3Jha3UtcHJvZ3JhbW1pbmctbGFuZ3VhZ2UtZWNvc3lzdGVtLWFyY2hpdmUiPlJha3UgRWNvc3lzdGVtIEFyY2hpdmU8L2E+LCB1cCBmcm9tIDxlbT48ZW0+MTIxODE8L2VtPjwvZW0+IGluIDIwMjQsIHdoaWNoIG1lYW5zIG1vcmUgdGhhbiA8ZW0+NC40PC9lbT4gbW9kdWxlIHVwZGF0ZXMgLyBkYXkgb24gYXZlcmFnZSBpbiAyMDI1ICh1cCBmcm9tIDxlbT4zLjk8L2VtPiB1cGRhdGVzIC8gZGF5KS48L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+SW50ZXJlc3RpbmcgbmV3IG1vZHVsZXM8L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5UaGUgbW9kdWxlcyB0aGF0IHlvdXJzIHRydWx5IGZvdW5kIGludGVyZXN0aW5nLCBzbyBhIHZlcnkgcGVyc29uYWwgbGlzdCEgIEluIGFscGhhYmV0aWNhbCBvcmRlcjo8L3A+CgoKCjx1bCBjbGFzcz0id3AtYmxvY2stbGlzdCI+CjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6YmR1Z2dhbi9BSTo6R2F0b3IiPkFJOjpHYXRvcjwvYT4gJiM4MjExOyBBSSBHZW5lcmljIEFzc2lzdGFudCB3aXRoIGEgVG9vbC1PcmllbnRlZCBSRVBMLjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6bGlicmFzdGV2ZS9BaXIiPkFpcjwvYT4gJiM4MjExOyBKdXN0IGJ1aWxkIHdlYnNpdGVzIHRoZSByaWdodCB3YXkuICBTZWUgYWxzbyA8YSBocmVmPSJodHRwczovL3Jha3UtYWR2ZW50LmJsb2cvMjAyNS8xMi8yMC9kYXktMjAtd2VyZS13YWxraW5nLW9uLXRoZS1haXIvIj5XZeKAmXJlIFdhbGtpbmcgT24gVGhlJm5ic3A7QWlyPC9hPi48L2xpPgoKCgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOnBhdHJpY2tiL0Fub2xpcyI+QW5vbGlzPC9hPiAmIzgyMTE7IEEgVGVybWluYWwgRW11bGF0b3IuICBTZWUgYWxzbyA8YSBocmVmPSJodHRwczovL3Jha3UtYWR2ZW50LmJsb2cvMjAyNS8xMi8yMS9hLXRlcm1pbmFscy10YWxlLyI+QSBUZXJtaW5hbOKAmXMgVGFsZTwvYT4uPC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpGQ08vQVNUUXVlcnkiPkFTVFF1ZXJ5PC9hPiAmIzgyMTE7IFF1ZXJ5IGFuZCBtYW5pcHVsYXRlIFJha3XigJlzIEFic3RyYWN0IFN5bnRheCBUcmVlcyAoUmFrdUFTVCkgd2l0aCBhbiBleHByZXNzaXZlIHN5bnRheC4gIFNlZSBhbHNvIDxhIGhyZWY9Imh0dHBzOi8vZGV2LnRvL2Zjby9mcm9tLWFzdHMtdG8tcmFrdWFzdC10by1hc3RxdWVyeS1jM2YiPkZyb20gQVNUcyB0byBSYWt1QVNUIHRvIEFTVFF1ZXJ5PC9hPi48L2xpPgoKCgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOkZDTy9Dcm9tcG9uZW50Ij5Dcm9tcG9uZW50PC9hPiAmIzgyMTE7IEEgd2F5IGNyZWF0ZSB3ZWIgY29tcG9uZW50cyB3aXRoIGNybyB0ZW1wbGF0ZXMuICBTZWUgYWxzbyA8YSBocmVmPSJodHRwczovL2Rldi50by9mY28vY3JvbXBvbmVudC1uZXctZmVhdHVyZXMtM2JoZiI+Q3JvbXBvbmVudCBuZXcgZmVhdHVyZXM8L2E+LjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6YXJ1bnZpY2tyYW0vRGF0YVN0YXIiPkRhdGFTdGFyPC9hPiAmIzgyMTE7IEEgUmFrdSBTREsgZm9yIHRoZSBkYXRhLXN0YXIgaHlwZXIgbWVkaWEgZnJhbWV3b3JrLiBTZWUgYWxzbyA8YSBocmVmPSJodHRwczovL3Jha3UtYWR2ZW50LmJsb2cvMjAyNS8xMi8xMS9kYXktMTEtcmFrdS10by10aGUtc3RhcnMvIj5SYWt1IFRvIFRoZSZuYnNwO1N0YXJzPC9hPi48L2xpPgoKCgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOmJkdWdnYW4vRHJha3UiPkRyYWt1PC9hPiAmIzgyMTE7IEEgZG9jdW1lbnRhdGlvbiBicm93c2VyIGZvciBSYWt1LjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6ZmluYW5hbHlzdC9FbHVjaWQ4OjpCdWlsZCI+RWx1Y2lkODo6QnVpbGQ8L2E+ICYjODIxMTsgUmVuZGVycyBSYWt1RG9jIHNvdXJjZXMgaW4gbXVsdGlwbGUgbGFuZ3VhZ2VzIHRvIHdlYiBzaXRlLiAgU2VlIGFsc28gPGEgaHJlZj0iaHR0cHM6Ly9kZXYudG8vZmluYW5hbHlzdC9jcmVhdGUtYS1taW5pbWFsLXNpdGUtd2l0aC1lbHVjaWQ4LTFnZjgiPkNyZWF0ZSBhIG1pbmltYWwgc2l0ZSB3aXRoIEVsdWNpZDg8L2E+LjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6bWFydGltbS9Hbm9tZTo6R3RrNCI+R25vbWU6Okd0azQ8L2E+ICYjODIxMTsgVGhlIGxhbmd1YWdlIGJpbmRpbmcgdG8mbmJzcDtHTk9NReKAmXMgdXNlciBpbnRlcmZhY2UgdG9vbGtpdCB2ZXJzaW9uIDQuICBTZWUgYWxzbyA8YSBocmVmPSJodHRwczovL3Jha3UtYWR2ZW50LmJsb2cvMjAyNS8xMi8wNS9kYXktNS10b29scy1mb3ItZ25vbWVndGs0LyI+VG9vbHMgZm9yJm5ic3A7R25vbWU6Okd0azQ8L2E+LjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6YW50b25vbmN1YmUvTExNOjpHcmFwaCI+TExNOjpHcmFwaDwvYT4gJiM4MjExOyBFZmZpY2llbnRseSBzY2hlZHVsZSBhbmQgY29tYmluZSBtdWx0aXBsZSBMTE0gZ2VuZXJhdGlvbiBzdGVwcy4gIFNlZSBhbHNvIDxhIGhyZWY9Imh0dHBzOi8vcmFrdS1hZHZlbnQuYmxvZy8yMDI1LzEyLzA2L2RheS02LXJvYnVzdC1jb2RlLWdlbmVyYXRpb24tY29tYmluaW5nLWdyYW1tYXJzLWFuZC1sbG1zLyI+Um9idXN0IGNvZGUgZ2VuZXJhdGlvbiBjb21iaW5pbmcgZ3JhbW1hcnMgYW5kJm5ic3A7TExNczwvYT4uPC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjphbnRvbm9uY3ViZS9NYXRoOjpOdW1iZXJUaGVvcnkiPk1hdGg6Ok51bWJlclRoZW9yeTwvYT4gJiM4MjExOyBSYWt1IHBhY2thZ2Ugd2l0aCBOdW1iZXIgdGhlb3J5IGZ1bmN0aW9ucy4gIFNlZSBhbHNvIDxhIGhyZWY9Imh0dHBzOi8vcmFrdS1hZHZlbnQuYmxvZy8yMDI1LzEyLzIyL2RheS0yMi1udW1lcmljYWxseS0yMDI2LWlzLXVucmVtYXJrYWJsZS15ZXQtaGFwcHkvIj5OdW1lcmljYWxseSAyMDI2IElzIFVucmVtYXJrYWJsZSBZZXQmbmJzcDtIYXBweTwvYT4uPC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpsaXptYXQvU0JPTTo6UmFrdSI+U0JPTTo6UmFrdTwvYT4gJiM4MjExOyBSYWt1Jm5ic3A7c3BlY2lmaWMmbmJzcDtTQk9NJm5ic3A7ZnVuY3Rpb25hbGl0eS4gIFNlZSBhbHNvIDxhIGhyZWY9Imh0dHBzOi8vZGV2LnRvL2xpem1hdC90b3dhcmRzLW1vcmUtYWNjb3VudGFiaWxpdHktb2YtcmFrdS1wcm9ncmFtcy0zZzIiPlRvd2FyZHMgbW9yZSBhY2NvdW50YWJpbGl0eSBvZiBSYWt1IHByb2dyYW1zPC9hPi48L2xpPgoKCgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOmxpem1hdC9UZXN0OjpDb3ZlcmFnZSI+VGVzdDo6Q292ZXJhZ2U8L2E+ICYjODIxMTsgQ2hlY2smbmJzcDt0ZXN0Jm5ic3A7ZmlsZXMgZm9yIHN1ZmZpY2llbnQmbmJzcDtjb3ZlcmFnZS4gIFNlZSBhbHNvIDxhIGhyZWY9Imh0dHBzOi8vZGV2LnRvL2xpem1hdC90b3dhcmRzLW1vcmUtY292ZXJhZ2UtZm5lIj5Ub3dhcmRzIG1vcmUgY292ZXJhZ2U8L2E+LjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6bGl6bWF0L1RleHQ6OkVtb2ppIj5UZXh0OjpFbW9qaTwvYT4gJiM4MjExOyBQcm92aWRlIDp0ZXh0OiB0byZuYnNwO2Vtb2ppJm5ic3A7dHJhbnNsYXRpb248L2xpPgoKCgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOnRvbnktby9aZWNvIj5aZWNvPC9hPiAmIzgyMTE7IEFuIGVjb3N5c3RlbSBob3N0aW5nIG1vZHVsZSBmb3IgcmFrdS4gU2VlIGFsc28gPGEgaHJlZj0iaHR0cHM6Ly9uZXdzLnBlcmxmb3VuZGF0aW9uLm9yZy9wb3N0L3Jha3UtZWNvc3lzdGVtLXRvbnlvLWZpbmFsIj5HcmFudCBSZXBvcnQ6IFJha3UgRWNvc3lzdGVtIEZpbmFsPC9hPi48L2xpPgo8L3VsPgoKCgo8aDQgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPk1vZHVsZXMgd2l0aCBub3RhYmxlIHVwZGF0ZXM8L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5BbHNvIGluIGFscGhhYmV0aWNhbCBvcmRlcjo8L3A+CgoKCjx1bCBjbGFzcz0id3AtYmxvY2stbGlzdCI+CjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6bGl6bWF0L0FwcDo6UmFrIj5BcHA6OlJhazwvYT4gJiM4MjExOyAyMXN0IGNlbnR1cnkgZ3JlcCAvIGZpbmQgLyBhY2sgLyBhZyAvIHJnIG9uIHN0ZXJvaWRzPC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpjcm8vY3JvIj5Dcm88L2E+ICYjODIxMTsgPHN0cm9uZz5jcm88L3N0cm9uZz4mbmJzcDtjb21tYW5kIGxpbmUgYW5kIHdlYiB0b29sPC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpkd2FycmluZy9QREYiPlBERjwvYT4gJiM4MjExOyBCYXNlIGNsYXNzZXMgZm9yIHJlYWRpbmcsIG1hbmlwdWxhdGlvbiBhbmQgd3JpdGluZyBvZiZuYnNwO1BERiZuYnNwO2RhdGE8L2xpPgoKCgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOkZDTy9SZWQiPlJlZDwvYT4gJiM4MjExOyBBIFJha3UgT1JNPC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpsaXptYXQvUkVQTCI+UkVQTDwvYT4gJiM4MjExOyBBIG1vcmUgZWFzaWx5IGNvbmZpZ3VyYWJsZSZuYnNwO1JFUEwuICBTZWUgYWxzbyA8YSBocmVmPSJodHRwczovL2Rldi50by9saXptYXQvcmVwbC1hdmFsYW5jaGUtNDVoaCI+UkVQTCBBdmFsYW5jaGU8L2E+LjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6ZmluYW5hbHlzdC9SYWt1YXN0OjpSYWt1RG9jOjpSZW5kZXIiPlJha3Vhc3Q6OlJha3Vkb2M6OlJlbmRlcmVyPC9hPiAmIzgyMTE7IHJlbmRlcnMgUmFrdURvYyB2MiB0byB0ZXh0LCBIVE1MLCBIVE1MLUV4dHJhLCBNYXJrZG93bi48L2xpPgoKCgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOmxpem1hdC9TbGFuZzo6Tm9naWwiPlNsYW5nOjpOb2dpbDwvYT4gJiM4MjExOyBhbGxvdyBzaWdpbGxlc3Mgc2NhbGFyIHZhcmlhYmxlcy4gIFNlZSBhbHNvIDxhIGhyZWY9Imh0dHBzOi8vcmFrdS1hZHZlbnQuYmxvZy8yMDI1LzEyLzA3L2RheS03LWFsbG93aW5nLWZvci1mZXdlci1kb2xsYXJzLyI+QWxsb3dpbmcgZm9yIGZld2VyJm5ic3A7ZG9sbGFyczwvYT4uPC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpqYXBoYi9UZXJtaW5hbDo6TGluZUVkaXRvciI+VGVybWluYWw6OkxpbmVFZGl0b3I8L2E+ICYjODIxMTsgR2VuZXJhbGl6ZWQmbmJzcDt0ZXJtaW5hbCZuYnNwO2xpbmUgZWRpdGluZzwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6dWdleGUvemVmIj56ZWY8L2E+ICYjODIxMTsgUmFrdSBNb2R1bGUgTWFuYWdlbWVudDwvbGk+CjwvdWw+CgoKCjxoMyBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+Qm90czwvaDM+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkEgbmV3IGV4cGVyaW1lbnRhbCBib3QgaGFzIGFwcGVhcmVkIG9uIHRoZSAjcmFrdS1kZXYgSVJDIGNoYW5uZWw6IDxjb2RlPnJha2thYmxlPC9jb2RlPi4gIEl0IGlzIGJhc2ljYWxseSBhbiBpbnRlcmFjdGl2ZSBmcm9udCBlbmQgZm9yIHRoZSA8YSBocmVmPSJodHRwczovL3Jha3UubGFuZC96ZWY6bGl6bWF0L0FwcDo6UmFrL2NoYW5nZXM/dj0wLjMuMTkiPm5ldyAmIzgyMjA7cmFrdWRvLXh4eCYjODIyMTs8L2E+IGZlYXR1cmVzIG9mIDxjb2RlPjxhIGhyZWY9Imh0dHBzOi8vcmFrdS5sYW5kL3plZjpsaXptYXQvQXBwOjpSYWsiPkFwcDo6UmFrPC9hPjwvY29kZT4uICBXaGljaCBpbiB0dXJuIGlzIGJhc2VkIG9uIHRoZSBuZXcgPGEgaHJlZj0iaHR0cHM6Ly9yYWt1LmxhbmQvemVmOmxpem1hdC9FY29zeXN0ZW06OkNhY2hlIj5FY29zeXN0ZW06OkNhY2hlPC9hPiBtb2R1bGUuICBUaGlzIGFsbG93cyBlYXN5IHNlYXJjaGluZyBpbiBhbGwgPHN0cm9uZz5tb3N0IGN1cnJlbnQ8L3N0cm9uZz4gdmVyc2lvbnMgb2YgbW9kdWxlcyBpbiB0aGUgZWNvc3lzdGVtLjwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+Rm9yIGluc3RhbmNlOiBsb29rIGluIHRoZSBSYWt1IGVjb3N5c3RlbSBmb3IgY29kZSBtZW50aW9uZWQgaW4gJiM4MjIwO3Byb3ZpZGVzJiM4MjIxOyBzZWN0aW9ucyB0aGF0IGNvbnRhaW4gdGhlIHN0cmluZyAmIzgyMjA7TG9jay5uZXcmIzgyMjE7IGFuZCB3aGljaCA8c3Ryb25nPmFsc288L3N0cm9uZz4gaGF2ZSB0aGUgc3RyaW5nICYjODIyMDskIWxvY2smIzgyMjE7OjwvcD4KCgoKPHByZSBjbGFzcz0id3AtYmxvY2stY29kZSBoYXMtZm9yZWdyb3VuZC1iYWNrZ3JvdW5kLWNvbG9yIGhhcy1iYWNrZ3JvdW5kIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjhweDtmb250LXNpemU6MTZweCI+PGNvZGU+Jmx0O2xpem1hdCZndDsgcmFra2FibGU6IDxtYXJrIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMCwgMCwgMCwgMCk7Y29sb3I6IzRhZWExYiIgY2xhc3M9Imhhcy1pbmxpbmUtY29sb3IiPjxzdHJvbmc+ZWNvLXByb3ZpZGVzIExvY2submV3IC0tYW5kPSQhbG9jazwvc3Ryb25nPjwvbWFyaz4KJmx0O3Jha2thYmxlJmd0OyBSdW5uaW5nOiBlY28tcHJvdmlkZXMgTG9jay5uZXcgLS1hbmQ9JCFsb2NrLCBwbGVhc2UgYmUgcGF0aWVudCEKJmx0O3Jha2thYmxlJmd0OyBGb3VuZCAzMCBsaW5lcyBpbiAyNSBmaWxlcyAoMjQgZGlzdHJpYnV0aW9ucyk6CiZsdDtyYWtrYWJsZSZndDsgaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vZmEyNDI0YWViZjA4NWVhNjU2YjQzNmM2MzcyMmJmOWQ8L2NvZGU+PC9wcmU+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRoZSBib3QgY3VycmVudGx5IG9ubHkgbGl2ZXMgb24gdGhlICNyYWt1LWRldiwgYnV0IGNhbiBhbHNvIGJlIGFjY2Vzc2VkIGRpcmVjdGx5IHdpdGhvdXQgbmVlZGluZyB0aGUgJiM4MjIwO3Jha2thYmxlOiYjODIyMTsgcHJlZml4LjwvcD4KCgoKPGgyIGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5Ob24tdGVjaG5pY2FsIHN0dWZmPC9oMj4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+WWVzLCB0aGVyZSYjODIxNztzIGFsc28gbm9uLXRlY2huaWNhbCBzdHVmZiBpbiB0aGUgUmFrdSB3b3JsZCE8L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+V2Vic2l0ZXM8L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5UaGUgPGEgaHJlZj0iaHR0cHM6Ly9yYWt1Lm9yZyI+cmFrdS5vcmc8L2E+IHdlYnNpdGUgaGFzIGJlZW4gY29tcGxldGVseSByZW5ld2VkLCB0aGFua3MgdG8gPGVtPlN0ZXZlIFJvZTwvZW0+IHdobyBoYXMgdGFrZW4gdGhhdCBvbi4gIEl0JiM4MjE3O3Mgbm93IGNvbXBsZXRlbHkgZG9nZm9vZGVkOiA8ZW0+aHlwZXJlZCB3aXRoJm5ic3A7PC9lbT48YSBocmVmPSJodHRwczovL2h0bXgub3JnLyIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9yZWZlcnJlciBub29wZW5lciI+aHRteDwvYT48ZW0+LiBBbG9mdCBvbiZuYnNwOzwvZW0+PGEgaHJlZj0iaHR0cHM6Ly9oYXJjc3RhY2sub3JnLyIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9yZWZlcnJlciBub29wZW5lciI+PHN0cm9uZz7DhWlyPC9zdHJvbmc+PC9hPjxlbT4uIENvbnN0cnVjdGVkIGluJm5ic3A7PC9lbT48YSBocmVmPSJodHRwczovL2Nyby5yYWt1Lm9yZy8iIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vcmVmZXJyZXIgbm9vcGVuZXIiPmNybzwvYT48ZW0+LiBXcml0dGVuIGluJm5ic3A7PC9lbT48YSBocmVmPSJodHRwczovL3Jha3Uub3JnLyIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9yZWZlcnJlciBub29wZW5lciI+cmFrdTwvYT48ZW0+LiAmbmJzcDsmYW1wOyZuYnNwOyBTdHlsZWQgYnkmbmJzcDs8L2VtPjxhIGhyZWY9Imh0dHBzOi8vcGljb2Nzcy5jb20vIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub3JlZmVycmVyIG5vb3BlbmVyIj5waWNvY3NzPC9hPjxlbT4uPC9lbT48L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+RG9jdW1lbnRhdGlvbjwvaDQ+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlRoZSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vcmFrdS9kb2M/dGFiPXJlYWRtZS1vdi1maWxlI29mZmljaWFsLWRvY3VtZW50YXRpb24tb2YtcmFrdSI+UmFrdSBEb2N1bWVudGF0aW9uIFByb2plY3Q8L2E+IGhhcyBnYWluZWQgcXVpdGUgYSBmZXcgY29sbGFib3JhdG9ycywgd2hvIGFyZSB3b3JraW5nIG9uIG1ha2luZyB0aGUgPGEgaHJlZj0iaHR0cHM6Ly9kb2NzLnJha3Uub3JnIj5SYWt1IGRvY3VtZW50YXRpb248L2E+IG1vcmUgYWNjZXNzaWJsZSB0byBuZXcgdXNlcnMuICBPbmUgZmFjdG9yIG1ha2luZyB0aGlzIGVhc2llciwgaXMgdGhhdCB0aGUgQ0kgdGVzdGluZyBmb3IgdGhlIGRvY3VtZW50YXRpb24gaGFzIGJlY29tZSBhYm91dCA0eCBhcyBmYXN0IGJ5IHVzaW5nIFJha3VBU1QgUmFrdURvYyBwYXJzaW5nLjwvcD4KCgoKPGg0IGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5Tb2NpYWwgTWVkaWE8L2g0PgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5Zb3VycyB0cnVseSBzdG9wcGVkIHVzaW5nIHdoYXQgaXMgbm93IFggKGZvcm1lcmx5IFR3aXR0ZXIpLiAgSXQgaHVydC4gIEJ1dCA8YSBocmVmPSJodHRwczovL2Jza3kuYXBwIj5CbHVlc2t5PC9hPiBhbmQgPGEgaHJlZj0iaHR0cHM6Ly9tYXN0b2Rvbi5zb2NpYWwvZXhwbG9yZSI+TWFzdG9kb248L2E+IGFyZSBnb29kIGFsdGVybmF0aXZlcywgYW5kIHRoZSBwZW9wbGUgaW1wb3J0YW50IHRvIHlvdXJzIHRydWx5IGhhdmUgbW92ZWQgdG8gdGhlbS4gIElmIHlvdSBoYXZlbiYjODIxNzt0IHlldCwgeW91IHByb2JhYmx5IHNob3VsZC4gIEFzIHdlbGwgYXMgdGhlIHBlb3BsZSBpbXBvcnRhbnQgdG8geW91LjwvcD4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+UGxlYXNlIGJlIHN1cmUgdG8gbWVudGlvbiB0aGUgPHN0cm9uZz4jcmFrdWxhbmc8L3N0cm9uZz4gdGFnIHdoZW4gcG9zdGluZyBhYm91dCB0aGUgPGEgaHJlZj0iaHR0cHM6Ly9yYWt1Lm9yZyI+UmFrdSBQcm9ncmFtbWluZyBMYW5ndWFnZTwvYT4hPC9wPgoKCgo8aDQgY2xhc3M9IndwLWJsb2NrLWhlYWRpbmciPkNvbmZlcmVuY2UgLyBDb3JlIFN1bW1pdDwvaDQ+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPlNhZGx5IGl0IGhhcyB0dXJuZWQgb3V0IHRvIGJlIGltcG9zc2libGUgdG8gb3JnYW5pemUgYSBSYWt1IENvbmZlcmVuY2UgKG5laXRoZXIgaW4tcGVyc29uIG9yIG9ubGluZSkgdGhpcyB5ZWFyLiAgSG9waW5nIGZvciBiZXR0ZXIgdGltZXMgbmV4dCB5ZWFyISAgSXQganVzdCByZWFsbHkgZGVwZW5kcyBvbiBwZW9wbGUgd2FudGluZyB0byBwdXQgaW4gdGhlIGVmZm9ydCE8L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkl0IDxzdHJvbmc+d2FzPC9zdHJvbmc+IHBvc3NpYmxlIHRvIG9yZ2FuaXplIGEgPGEgaHJlZj0iaHR0cHM6Ly9kZXYudG8vcGF0cmlja2Jrci90aGUtc2Vjb25kLXJha3UtY29yZS1zdW1taXQtM2QyIj5zZWNvbmQgUmFrdSBDb3JlIFN1bW1pdDwvYT4gaW4gMjAyNSE8L3A+CgoKCjxoNCBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+V2Vla2x5PC9oND4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIDxhIGhyZWY9Imh0dHBzOi8vcmFrdWRvd2Vla2x5LmJsb2cvYmxvZy1mZWVkLyI+UmFrdWRvIFdlZWtseSBOZXdzPC9hPiBoYXMgYmVlbiBicm91Z2h0IHRvIHlvdSBieSA8ZW0+U3RldmUgUm9lPC9lbT4gaW4gdGhlIDJuZCBoYWxmIG9mIDIwMjUgKGFuZCBmb3IgdGhlIGZvcmVzZWVhYmxlIGZ1dHVyZSkuICBXaXRoIHNvbWUgbmV3IGZlYXR1cmVzLCBzdWNoIGFzIGNvZGUgZ2lzdHMhICBLdWRvcyE8L3A+CgoKCjxoMyBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+UHJvYmxlbSBTb2x2aW5nPC9oMz4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+VGhlIDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9SYWt1L3Byb2JsZW0tc29sdmluZz90YWI9cmVhZG1lLW92LWZpbGUjLXByb2JsZW0tc29sdmluZyI+UHJvYmxlbSBTb2x2aW5nIHJlcG9zaXRvcnk8L2E+IGhhcyBzZWVuIGFuIGluZmx1eCBvZiA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vUmFrdS9wcm9ibGVtLXNvbHZpbmcvaXNzdWVzP3E9aXMlM0Fpc3N1ZSUyMHN0YXRlJTNBb3BlbiUyMGNyZWF0ZWQlM0ElM0UyMDI0LTEyLTI0JTIwY3JlYXRlZCUzQSUzQzIwMjUtMTItMjUiPjxzdHJvbmc+MzY8L3N0cm9uZz4gbmV3IGlzc3VlczwvYT4gdGhlIHBhc3QgeWVhci4gVGhleSA8c3Ryb25nPjxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9SYWt1L3Byb2JsZW0tc29sdmluZy9pc3N1ZXMiPmFsbDwvYT48L3N0cm9uZz4gZGVzZXJ2ZSB5b3VyIGF0dGVudGlvbiBhbmQgeW91ciBmZWVkYmFjayEgU29tZSBvZiB0aGVtIHNwZWNpZmljYWxseSBhc2sgZm9yIHlvdXIgaWRlYXMsIHN1Y2ggYXM6PC9wPgoKCgo8dWwgY2xhc3M9IndwLWJsb2NrLWxpc3QiPgo8bGk+PGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL1Jha3UvcHJvYmxlbS1zb2x2aW5nL2lzc3Vlcy81MDIiPkZ1cnRoZXIgSW1wcm92ZW1lbnRzIHRvIHRoZSBSYWt1IFdlYnNpdGUgTGFuZHNjYXBlPC9hPjwvbGk+CgoKCjxsaT48YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vUmFrdS9wcm9ibGVtLXNvbHZpbmcvaXNzdWVzLzUwNyI+SW50ZXJlc3QgJmFtcDsgRW5nYWdlIHRoZSBOZXh0IDEwMDAgUmFrdSBjb2RlcnM8L2E+PC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9SYWt1L3Byb2JsZW0tc29sdmluZy9pc3N1ZXMvNDkxIj5QcmVwYXJpbmcgbW9kdWxlIE1FVEE2Lmpzb24gaW5mb3JtYXRpb24gZm9yIHRoZSBmdXR1cmU8L2E+PC9saT4KCgoKPGxpPjxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9SYWt1L3Byb2JsZW0tc29sdmluZy9pc3N1ZXMvNDg5Ij5SYWt1IENsYXNzaWZpY2F0aW9uIFN5c3RlbTwvYT48L2xpPgo8L3VsPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5QbGVhc2UsIGRvbiYjODIxNzt0IGJlIHNoeSBhbmQgaGF2ZSB5b3VyIHZvaWNlIGhlYXJkITwvcD4KCgoKPGgzIGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj5SYWt1IFN0ZWVyaW5nIENvdW5jaWw8L2gzPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5TYWRseSwgPGVtPlZhZGltIEJlbG1hbjwvZW0+IGFuZCA8ZW0+U3RlZmFuIFNlaWZlcnQ8L2VtPiBoYXZlIGluZGljYXRlZCB0aGF0IHRoZXkgd2FudGVkIHRvIHN0ZXAgZG93biBmcm9tIHRoZSBSYWt1IFN0ZWVyaW5nIENvdW5jaWwuIFRoZXkgYXJlIHRoYW5rZWQgZm9yIGFsbCB0aGF0IHRoZXkgaGF2ZSBkb25lIGZvciBSYWt1LCB0aGUgUmFrdSBDb21tdW5pdHkgaW4gZ2VuZXJhbCwgYW5kIHRoZSBSYWt1IFN0ZWVyaW5nIENvdW5jaWwgaW4gcGFydGljdWxhci48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPjxlbT5Kb2huIEhhbHRpd2FuZ2VyPC9lbT4gaGFzIGFjY2VwdGVkIGFuIGludml0YXRpb24gdG8gam9pbiB0aGUgUmFrdSBTdGVlcmluZyBDb3VuY2lsLiAgVGhlIHNlYXQgb3BlbmVkIGJ5IDxlbT5TdGVmYW4gU2VpZmVydDwvZW0+IHdpbGwgbm90IGJlIGZpbGxlZCBmb3IgYXQgbGVhc3QgdGhlIGNvbWluZyA2IG1vbnRocy48L3A+CgoKCjxoMyBjbGFzcz0id3AtYmxvY2staGVhZGluZyI+VGhlIFJha3UgRm91bmRhdGlvbjwvaDM+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkFmdGVyIHdyaXRpbmcgYSA8YSBocmVmPSJodHRwczovL2Rldi50by9saXptYXQvdG93YXJkcy1hLXJha3UtZm91bmRhdGlvbi0zbmUyIj5ibG9nIHBvc3QgYWJvdXQgYSBSYWt1IEZvdW5kYXRpb248L2E+LCBhIDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9SYWt1L3Byb2JsZW0tc29sdmluZy9pc3N1ZXMvNDc3Ij5wcm9ibGVtIHNvbHZpbmcgaXNzdWU8L2E+IGFuZCBtYW55IGRpc2N1c3Npb25zIGF0IHRoZSBzZWNvbmQgUmFrdSBDb3JlIFN1bW1pdCwgdGhlcmUgZmluYWxseSBpcyBhIHZlcnNpb24gb2YgdGhlIDxhIGhyZWY9Imh0dHBzOi8vbGl6bWF0LmdpdGh1Yi5pby9SYWt1LUZvdW5kYXRpb24tRG9jdW1lbnRzLyI+UmFrdSBGb3VuZGF0aW9uIERvY3VtZW50czwvYT4gdGhhdCBldmVyeWJvZHkgY2FuIGFncmVlIG9uIChhdCBsZWFzdCBmb3Igbm93KS48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPllvdXJzIHRydWx5IHVyZ2VzIHRoZSByZWFkZXJzIHRvIGNoZWNrIG91dCA8YSBocmVmPSJodHRwczovL2xpem1hdC5naXRodWIuaW8vUmFrdS1Gb3VuZGF0aW9uLURvY3VtZW50cy9hcnRpY2xlcy1vZi1hc3NvY2lhdGlvbi5odG1sIj5UaGUgQXJ0aWNsZXMgT2YgQXNzb2NpYXRpb248L2E+LCBhcyB0aGVzZSB3aWxsIGJlIHZlcnkgaGFyZCB0byBjaGFuZ2Ugb25jZSB0aGUgZm91bmRhdGlvbiBpcyBlc3RhYmxpc2hlZC48L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPklmIHlvdSBhcmUgcmVhbGx5IGludGVyZXN0ZWQgaW4gdGhpcyBraW5kIG9mIHN0dWZmLCBwbGVhc2UgY2hlY2sgb3V0IHRoZSA8YSBocmVmPSJodHRwczovL2xpem1hdC5naXRodWIuaW8vUmFrdS1Gb3VuZGF0aW9uLURvY3VtZW50cy9SYWt1Rm91bmRhdGlvblJlZ3VsYXRpb25zLmh0bWwiPlJlZ3VsYXRpb25zIGZvciB0aGUgb3BlcmF0aW9uIG9mIHRoZSBSYWt1IEZvdW5kYXRpb248L2E+IGFzIHdlbGwuPC9wPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5BbmQgaWYgeW91IHdvdWxkIGxpa2UgdG8gYmVjb21lIHBhcnQgb2YgdGhlIGluaXRpYWwgPGEgaHJlZj0iaHR0cHM6Ly9saXptYXQuZ2l0aHViLmlvL1Jha3UtRm91bmRhdGlvbi1Eb2N1bWVudHMvYXJ0aWNsZXMtb2YtYXNzb2NpYXRpb24uaHRtbCNUaGVfRXhlYyI+RXhlY3V0aXZlIEJvYXJkPC9hPiBvciB0aGUgPGEgaHJlZj0iaHR0cHM6Ly9saXptYXQuZ2l0aHViLmlvL1Jha3UtRm91bmRhdGlvbi1Eb2N1bWVudHMvYXJ0aWNsZXMtb2YtYXNzb2NpYXRpb24uaHRtbCNTdXBlciI+U3VwZXJ2aXNvcnkgQm9hcmQ8L2E+LCBwbGVhc2Ugc2VuZCBhbiBlbWFpbCB0byA8YSBocmVmPSJtYWlsdG86Zm91bmRpbmdAcmFrdS5mb3VuZGF0aW9uIj5mb3VuZGluZ0ByYWt1LmZvdW5kYXRpb248L2E+LjwvcD4KCgoKPGgzIGNsYXNzPSJ3cC1ibG9jay1oZWFkaW5nIj48YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vbGl6bWF0L2FydGljbGVzL2Jsb2IvbWFpbi9yZXZpZXctb2YtMjAyMi5tZCNzdW1tYXJ5Ij48L2E+U3VtbWFyeTwvaDM+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkxvb2tpbmcgYmFjaywgYWdhaW4gYW4gYW1hemluZyBhbW91bnQgb2Ygd29yayBoYXMgYmVlbiBkb25lIGluIDIwMjUhICBBbmQgbm90IG9ubHkgb24gdGhlIHRlY2huaWNhbCBzaWRlIG9mIHRoaW5ncyE8L3A+CgoKCjxwIGNsYXNzPSJ3cC1ibG9jay1wYXJhZ3JhcGgiPkhvcGVmdWxseSB5b3Ugd2lsbCBhbGwgYmUgYWJsZSB0byBlbmpveSB0aGUgSG9saWRheSBTZWFzb24gd2l0aCBzdWZmaWNpZW50IFImYW1wO1IuICBFc3BlY2lhbGx5IDxlbT48YSBocmVmPSJodHRwczovL2lyY2xvZ3MucmFrdS5vcmcvcmFrdS9naXN0Lmh0bWw/LDIwMjQtMDQtMjNaMTI6NDcsMjAyNC0wNC0yM1oxMjo0OCwyMDI0LTA0LTIzWjEyOjUwLTAwMDEsMjAyNC0wNC0yM1oxMjo1MiwyMDI0LTA0LTIzWjEzOjE0LDIwMjQtMDQtMjNaMTQ6MzQiPkthbmUgVmFsZW50aW5lPC9hPjwvZW0+IChha2EgPGVtPmthd2FpaTwvZW0+KSB3aG8gaXMgc3RpbGwgZ29pbmcgc3Ryb25nIGluIHRoZWlyIG5ldyByb2xlOjwvcD4KCgoKPGZpZ3VyZSBjbGFzcz0id3AtYmxvY2staW1hZ2Ugc2l6ZS1sYXJnZSI+PGltZyB3aWR0aD0iNjM0IiBoZWlnaHQ9IjY0NSIgZGF0YS1hdHRhY2htZW50LWlkPSI0NzQ5IiBkYXRhLXBlcm1hbGluaz0iaHR0cHM6Ly9yYWt1LWFkdmVudC5ibG9nLzIwMjUvMTIvMjUvZGF5LTI1LXJha3UtMjAyNS1yZXZpZXcvaW1hZ2UtMTUvIiBkYXRhLW9yaWctZmlsZT0iaHR0cHM6Ly9yYWt1LWFkdmVudC5ibG9nL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDI1LzEyL2ltYWdlLTIucG5nIiBkYXRhLW9yaWctc2l6ZT0iNjM0LDY0NSIgZGF0YS1jb21tZW50cy1vcGVuZWQ9IjEiIGRhdGEtaW1hZ2UtbWV0YT0ieyZxdW90O2FwZXJ0dXJlJnF1b3Q7OiZxdW90OzAmcXVvdDssJnF1b3Q7Y3JlZGl0JnF1b3Q7OiZxdW90OyZxdW90OywmcXVvdDtjYW1lcmEmcXVvdDs6JnF1b3Q7JnF1b3Q7LCZxdW90O2NhcHRpb24mcXVvdDs6JnF1b3Q7JnF1b3Q7LCZxdW90O2NyZWF0ZWRfdGltZXN0YW1wJnF1b3Q7OiZxdW90OzAmcXVvdDssJnF1b3Q7Y29weXJpZ2h0JnF1b3Q7OiZxdW90OyZxdW90OywmcXVvdDtmb2NhbF9sZW5ndGgmcXVvdDs6JnF1b3Q7MCZxdW90OywmcXVvdDtpc28mcXVvdDs6JnF1b3Q7MCZxdW90OywmcXVvdDtzaHV0dGVyX3NwZWVkJnF1b3Q7OiZxdW90OzAmcXVvdDssJnF1b3Q7dGl0bGUmcXVvdDs6JnF1b3Q7JnF1b3Q7LCZxdW90O29yaWVudGF0aW9uJnF1b3Q7OiZxdW90OzAmcXVvdDt9IiBkYXRhLWltYWdlLXRpdGxlPSJpbWFnZSIgZGF0YS1pbWFnZS1kZXNjcmlwdGlvbj0iIiBkYXRhLWltYWdlLWNhcHRpb249IiIgZGF0YS1tZWRpdW0tZmlsZT0iaHR0cHM6Ly9yYWt1LWFkdmVudC5ibG9nL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDI1LzEyL2ltYWdlLTIucG5nP3c9Mjk1IiBkYXRhLWxhcmdlLWZpbGU9Imh0dHBzOi8vcmFrdS1hZHZlbnQuYmxvZy93cC1jb250ZW50L3VwbG9hZHMvMjAyNS8xMi9pbWFnZS0yLnBuZz93PTYzNCIgc3JjPSJodHRwczovL3Jha3UtYWR2ZW50LmJsb2cvd3AtY29udGVudC91cGxvYWRzLzIwMjUvMTIvaW1hZ2UtMi5wbmc/dz02MzQiIGFsdD0iIiBjbGFzcz0id3AtaW1hZ2UtNDc0OSIgc3Jjc2V0PSJodHRwczovL3Jha3UtYWR2ZW50LmJsb2cvd3AtY29udGVudC91cGxvYWRzLzIwMjUvMTIvaW1hZ2UtMi5wbmcgNjM0dywgaHR0cHM6Ly9yYWt1LWFkdmVudC5ibG9nL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDI1LzEyL2ltYWdlLTIucG5nP3c9MTQ3IDE0N3csIGh0dHBzOi8vcmFrdS1hZHZlbnQuYmxvZy93cC1jb250ZW50L3VwbG9hZHMvMjAyNS8xMi9pbWFnZS0yLnBuZz93PTI5NSAyOTV3IiBzaXplcz0iKG1heC13aWR0aDogNjM0cHgpIDEwMHZ3LCA2MzRweCIgLz48L2ZpZ3VyZT4KCgoKPHAgY2xhc3M9IndwLWJsb2NrLXBhcmFncmFwaCI+QW5kIG9uIHRoYXQgbm90ZTog0KHQu9Cw0LLQsCDQo9C60YDQsNGX0L3RliEgJm5ic3A70JPQtdGA0L7Rj9C8INGB0LvQsNCy0LAhPC9wPgoKCgo8cCBjbGFzcz0id3AtYmxvY2stcGFyYWdyYXBoIj5UaGUgbmV4dCBSYWt1IEFkdmVudCBCbG9nIGlzIG9ubHkgMzQwIGRheXMgYXdheSE8L3A+Cg==</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">How time flies. Yet another year has flown by. Let’s first start with the technical stuff, as nerds do! Rakudo Rakudo saw about 1650 commits (MoarVM, NQP, Rakudo, doc) this year, which is about 20% less than 2024. All of these repositories now have “main” as their default branch (rather than “master”). About 58% of<a class="more-link" href="https://raku-advent.blog/2025/12/25/day-25-raku-2025-review/">Continue reading <span class="screen-reader-text">"Day 25 – Raku 2025 Review"</span></a></div>
    </summary>
    <author>
      <name>Elizabeth Mattijsen</name>
    </author>
    <id>http://raku-advent.blog/?p=4583</id>
    <published>2025-12-25T01:00:00Z</published>
    <updated>2025-12-25T01:00:00Z</updated>
    <category term="2025"/>
    <category term="Advent"/>
    <category term="Raku"/>
    <category term="rakulang"/>
    <category term="review"/>
  </entry>
  <entry>
    <title>Day 24 – Maze Making Using Graphs</title>
    <link rel="alternate" href="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/" type="text/html"/>
    <content type="html">
&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Introduction&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;This document (&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/Maze-making-using-graphs.ipynb"&gt;notebook&lt;/a&gt;) describes three ways of making mazes (or labyrinths) using graphs. The first two are based on rectangular grids; the third on a hexagonal grid.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;All computational graph features discussed here are provided by&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/Graph"&gt;&amp;#8220;Graph&amp;#8221;&lt;/a&gt;, [AAp1]. The package used for the construction of the third, hexagonal graph is&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/Math::Nearest"&gt;&amp;#8220;Math::Nearest&amp;#8221;&lt;/a&gt;, [AAp2].&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;TL;DR&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Just see the maze pictures below. (And try to solve the mazes.)&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Procedure outline&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;The first maze is made by a simple procedure which is actually some sort of cheating:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;A regular rectangular grid graph is generated with random weights associated with its edges.&lt;/li&gt;



&lt;li&gt;The (minimum) spanning tree for that graph is found.&lt;/li&gt;



&lt;li&gt;That tree is plotted with exaggeratedly large vertices and edges, so the graph plot looks like a maze.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;This is &amp;#8220;the cheat&amp;#8221; — the maze walls are not given by the graph.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;The second maze is made &amp;#8220;properly&amp;#8221;:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Two interlacing regular rectangular grid graphs are created.&lt;/li&gt;



&lt;li&gt;The second one has one less row and one less column than the first.&lt;/li&gt;



&lt;li&gt;The vertex coordinates of the second graph are at the centers of the rectangles of the first graph.&lt;/li&gt;



&lt;li&gt;The first graph provides the maze walls; the second graph is used to make paths through the maze.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;In other words, to create a solvable maze.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Again, random weights are assigned to edges of the second graph, and a minimum spanning tree is found.&lt;/li&gt;



&lt;li&gt;There is a convenient formula that allows using the spanning tree edges to remove edges from the first graph.&lt;/li&gt;



&lt;li&gt;In that way, a proper maze is derived.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;The third maze is again made &amp;#8220;properly&amp;#8221; using the procedure above with two modifications:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Two interlacing regular grid graphs are created: one over a hexagonal grid, the other over a triangular grid.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;The hexagonal grid graph provides the maze walls; the triangular grid graph provides the maze paths.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Since the formula for wall removal is hard to derive, a more robust and universal method based on nearest neighbors is used.&lt;/li&gt;
&lt;/ul&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Setup&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Packages&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Here are the packages loaded for use in the rest of the notebook:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
use Graph;
use Graph::Classes;

use Math::DistanceFunctions;
use Math::Nearest;

use Data::TypeSystem;
use Data::Translators;
use Data::Generators;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Conversion&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;This sub is used to invoke the Graphviz graph layout engines:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
sub dot-svg($input, Str:D :$engine = 'dot', Str:D :$format = 'svg') {
    my $temp-file = $*TMPDIR.child("temp-graph.dot");
    $temp-file.spurt: $input;
    my $svg-output = run($engine, $temp-file, "-T$format", :out).out.slurp-rest;
    unlink $temp-file;
    return $svg-output;
}

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Simple Maze&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;In this section, we create a simple, &amp;#8220;cheating&amp;#8221; maze.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;The steps are easy to follow, given the procedure outlined in the introduction.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
# Maze dimensions
my ($n, $m) = (10, 25);

# Base grid graph
my $g = Graph::Grid.new($n, $m, :!directed);

# Using the edges of the grid graph make a new graph assigned random edge weights
my $gWeighted = Graph.new($g.edges(:dataset).map({ $_&amp;lt;weight&amp;gt; = random-real(&amp;#91;10,1000]); $_}))

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 250, edges =&amp;gt; 465, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Find the spanning tree of the graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $mazePath = $gWeighted.find-spanning-tree

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 250, edges =&amp;gt; 249, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Shortest path from the first vertex (bottom-left) to the last vertex (top-right):&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my @path = $mazePath.find-shortest-path('0_0', "{$n-1}_{$m-1}");
@path.elems

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# 56

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Graph plot:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#% html
my $simpleMaze = Graph.new($mazePath.edges);
$simpleMaze.vertex-coordinates = $g.vertex-coordinates;

my %opts =
    background =&amp;gt; &amp;quot;Black&amp;quot;,
    :!node-labels,
    :!edge-lables,
    node-shape =&amp;gt; &amp;#039;square&amp;#039;, 
    node-width =&amp;gt; 0.7, 
    node-color =&amp;gt; &amp;#039;SteelBlue&amp;#039;,
    node-fill-color =&amp;gt; &amp;#039;SteelBlue&amp;#039;,
    edge-thickness =&amp;gt; 52, 
    edge-color =&amp;gt; &amp;#039;SteelBlue&amp;#039;,
    size =&amp;gt; &amp;#039;10,6!&amp;#039;,
    engine =&amp;gt; &amp;#039;neato&amp;#039;;

$simpleMaze.dot(|%opts):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4791" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/simple-maze-1/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-1.png" data-orig-size="1173,482" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Simple-maze-1" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-1.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-1.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-1.png" alt="" class="wp-image-4791" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;The &amp;#8220;maze&amp;#8221; above looks like a maze because the vertices and edges are rectangular with matching sizes, and they are thicker than the spaces between them. In other words, we are cheating.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;To make that cheating construction clearer, let us plot the shortest path from the bottom left to the top right and color the edges in pink (salmon) and the vertices in red:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#%html
my $gPath = Graph::Path.new(@path);
$simpleMaze.dot(highlight =&amp;gt; {Salmon =&amp;gt; $gPath.edge-list, Red =&amp;gt; $gPath.vertex-list}, |%opts):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4790" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/simple-maze-2-path/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-2-path.png" data-orig-size="1173,476" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Simple-maze-2-path" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-2-path.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-2-path.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/simple-maze-2-path.png" alt="" class="wp-image-4790" /&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Proper Maze&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;A&amp;nbsp;&lt;em&gt;&lt;strong&gt;proper maze&lt;/strong&gt;&lt;/em&gt;&amp;nbsp;is a maze given with its walls (not with the space between walls).&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;For didactical reasons, the maze in this section is small so that the steps—outlined in the introduction—can be easily followed.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Make two regular graphs: one for the maze walls and the other for the maze paths.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
# Maze dimensions
my ($n, $m) = (6, 12) »*» 1;

# Walls graph
my $g1 = Graph::Grid.new($n, $m, prefix =&amp;gt; &amp;#039;w&amp;#039;);

# Space graph
my $g2 = Graph::Grid.new($n-1, $m-1);
$g2.vertex-coordinates = $g2.vertex-coordinates.map({ $_.key =&amp;gt; $_.value &amp;gt;&amp;gt;+&amp;gt;&amp;gt; 0.5 }).Hash;

$g2

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 55, edges =&amp;gt; 94, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Maze Path Graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $mazePath = Graph.new($g2.edges(:dataset).map({ $_&amp;lt;weight&amp;gt; = random-real(&amp;#91;10,1000]); $_}));
$mazePath = $mazePath.find-spanning-tree;
$mazePath.vertex-coordinates = $g2.vertex-coordinates;

$mazePath

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 55, edges =&amp;gt; 54, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Combined Graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $g3 = Graph.new(&amp;#91;|$g1.edges, |$mazePath.edges]);
$g3.vertex-coordinates = &amp;#91;|$g1.vertex-coordinates, |$mazePath.vertex-coordinates].Hash;

$g3

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 127, edges =&amp;gt; 180, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Plot the combined graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#% html
$g3.dot(
    highlight =&amp;gt; $mazePath,
    :node-labels,
    background =&amp;gt; &amp;quot;Black&amp;quot;,
    node-width =&amp;gt; 0.45,
    node-height =&amp;gt; 0.2,
    edge-width =&amp;gt; 4,
    size =&amp;gt; &amp;#039;10,10!&amp;#039;,
    engine =&amp;gt; &amp;#039;neato&amp;#039;
):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4796" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/proper-regular-grid-maze-1/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-1.png" data-orig-size="1174,578" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Proper-regular-grid-maze-1" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-1.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-1.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-1.png" alt="" class="wp-image-4796" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Remove wall edges using a formula:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $g4 = $g3.clone;
for $mazePath.edges -&amp;gt; $e {

    my ($i, $j) = |$e.key.split(&amp;#039;_&amp;#039;)».Int;
    my ($i2, $j2) = |$e.value.split(&amp;#039;_&amp;#039;)».Int;
    
    if $i2 &amp;lt; $i || $j2 &amp;lt; $j { 
        ($i2, $j2, $i, $j) = ($i, $j, $i2, $j2)
    }

    # Horizontal
    if $i == $i2 &amp;amp;&amp;amp; $j &amp;lt; $j2 {
        $g4 = $g4.edge-delete( &amp;quot;w{$i2}_{$j2}&amp;quot; =&amp;gt; &amp;quot;w{$i2+1}_{$j2}&amp;quot;)
    }

    # Vertical
    if $j == $j2 &amp;amp;&amp;amp; $i &amp;lt; $i2 {
        $g4 = $g4.edge-delete( &amp;quot;w{$i2}_{$j2}&amp;quot; =&amp;gt; &amp;quot;w{$i2}_{$j2+1}&amp;quot;)
    }
}

$g4

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 127, edges =&amp;gt; 126, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Plot wall graph and maze space graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#% html
$g4.dot(
    highlight =&amp;gt; $mazePath,
    :!node-labels,
    background =&amp;gt; &amp;quot;Black&amp;quot;,
    node-width =&amp;gt; 0.25,
    node-height =&amp;gt; 0.2,
    edge-width =&amp;gt; 4,
    size =&amp;gt; &amp;#039;10,10!&amp;#039;,
    engine =&amp;gt; &amp;#039;neato&amp;#039;
):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4792" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/proper-regular-grid-maze-2/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-2.png" data-orig-size="1177,569" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Proper-regular-grid-maze-2" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-2.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-2.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-2.png" alt="" class="wp-image-4792" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Fancier maze presentation with rectangular vertices and edges (with matching sizes):&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#% html
my $g5 = $g4.subgraph($g1.vertex-list);

my @path = $mazePath.find-shortest-path(&amp;#039;0_0&amp;#039;, &amp;quot;{$n-2}_{$m-2}&amp;quot;);
say @path.elems;

my @mazeStartEnd = &amp;quot;w0_0&amp;quot;, w0_0 =&amp;gt; &amp;quot;w0_1&amp;quot;, w0_0 =&amp;gt; &amp;quot;w1_0&amp;quot;, &amp;quot;w{$n-1}_{$m-1}&amp;quot;, &amp;quot;w{$n-1}_{$m-1}&amp;quot; =&amp;gt; &amp;quot;w{$n-1}_{$m-2}&amp;quot;, &amp;quot;w{$n-1}_{$m-1}&amp;quot; =&amp;gt; &amp;quot;w{$n-2}_{$m-1}&amp;quot;;

$g4.dot(
    highlight =&amp;gt; {&amp;#039;#1F1F1F&amp;#039; =&amp;gt; &amp;#91;|$mazePath.vertex-list, |$mazePath.edge-list, |@mazeStartEnd], Orange =&amp;gt; @path},
    #highlight =&amp;gt; {&amp;#039;#1F1F1F&amp;#039; =&amp;gt; @mazeStartEnd},
    background =&amp;gt; &amp;#039;#1F1F1F&amp;#039;,
    size =&amp;gt; &amp;#039;10,10!&amp;#039;,
    :!node-labels,
    node-shape =&amp;gt; &amp;#039;square&amp;#039;,
    node-color =&amp;gt; &amp;#039;SteelBlue&amp;#039;,
    node-fill-color =&amp;gt; &amp;#039;SteelBlue&amp;#039;,
    node-width =&amp;gt; 0.4,
    edge-width =&amp;gt; 30,
    engine =&amp;gt; &amp;#039;neato&amp;#039;
):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4789" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/proper-regular-grid-maze-3/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-3.png" data-orig-size="1175,570" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Proper-regular-grid-maze-3" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-3.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-3.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/proper-regular-grid-maze-3.png" alt="" class="wp-image-4789" /&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Hexagonal Version&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Let us create another maze based on a hexagonal grid. Here are two grid graphs:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;The first is a&amp;nbsp;&lt;strong&gt;hexagonal grid&lt;/strong&gt;&amp;nbsp;graph representing the maze&amp;#8217;s walls.&lt;/li&gt;



&lt;li&gt;The second graph is a&amp;nbsp;&lt;strong&gt;triangular grid&lt;/strong&gt;&amp;nbsp;graph with one fewer row and column, and shifted vertex coordinates.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
# Maze dimensions
my ($n, $m) = (6, 10) »*» 2;

# Walls graph
my $g1 = Graph::HexagonalGrid.new($n, $m, prefix =&amp;gt; &amp;#039;w&amp;#039;);

# Space graph
my $g2 = Graph::TriangularGrid.new($n-1, $m-1);
$g2.vertex-coordinates = $g2.vertex-coordinates.map({ $_.key =&amp;gt; $_.value &amp;gt;&amp;gt;+&amp;lt;&amp;lt; &amp;#91;sqrt(3), 1 ] }).Hash;

$g2

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
Graph(vertexes =&amp;gt; 240, edges =&amp;gt; 657, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#% html
$g1.union($g2).dot(
    highlight =&amp;gt; $g2,
    :!node-labels,
    background =&amp;gt; &amp;quot;#1F1F1F&amp;quot;,
    node-width =&amp;gt; 0.85,
    node-height =&amp;gt; 0.85,
    node-font-size =&amp;gt; 28,
    node-shape =&amp;gt; &amp;#039;hexagon&amp;#039;,
    edge-width =&amp;gt; 7,
    size =&amp;gt; &amp;#039;10,10!&amp;#039;,
    engine =&amp;gt; &amp;#039;neato&amp;#039;
):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4794" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/hexagonal-grid-maze-1/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-1.png" data-orig-size="1178,514" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Hexagonal-grid-maze-1" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-1.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-1.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-1.png" alt="" class="wp-image-4794" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Maze Path Graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $mazePath = Graph.new($g2.edges(:dataset).map({ $_&amp;lt;weight&amp;gt; = random-real(&amp;#91;10,1000]); $_}));
$mazePath = $mazePath.find-spanning-tree;
$mazePath = Graph.new($mazePath.edges);
$mazePath.vertex-coordinates = $g2.vertex-coordinates;

$mazePath

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 240, edges =&amp;gt; 239, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Combine the walls-maze and the maze-path graphs (i.e., make a union of them), and plot the resulting graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#% html

my $g3 = $g1.union($mazePath);

$g3.dot(
    highlight =&amp;gt; $mazePath,
    :node-labels,
    background =&amp;gt; &amp;quot;#1F1F1F&amp;quot;,
    node-width =&amp;gt; 0.85,
    node-height =&amp;gt; 0.85,
    node-font-size =&amp;gt; 28,
    node-shape =&amp;gt; &amp;#039;hexagon&amp;#039;,
    edge-width =&amp;gt; 7,
    size =&amp;gt; &amp;#039;10,10!&amp;#039;,
    engine =&amp;gt; &amp;#039;neato&amp;#039;
):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4795" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/hexagonal-grid-maze-2/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-2.png" data-orig-size="1175,517" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Hexagonal-grid-maze-2" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-2.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-2.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-2.png" alt="" class="wp-image-4795" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Make a nearest neighbor points finder functor:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my &amp;amp;finder = nearest($g1.vertex-coordinates.Array, method =&amp;gt; &amp;#039;KDTree&amp;#039;);


&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
Math::Nearest::Finder(Algorithm::KDimensionalTree(points =&amp;gt; 544, distance-function =&amp;gt; &amp;amp;euclidean-distance, labels =&amp;gt; 544))

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Take a maze edge and its vertex points:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $e = $mazePath.edges.head;
my @points = $g2.vertex-coordinates{($e.kv)};

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# &amp;#91;&amp;#91;-3.4641016151381225 -2] &amp;#91;-1.7320508075691228 1]]

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Find the edge&amp;#8217;s midpoint and the nearest wall-graph vertices:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my @m = |((@points.head &amp;lt;&amp;lt;+&amp;gt;&amp;gt; @points.tail) &amp;gt;&amp;gt;/&amp;gt;&amp;gt; 2);
say &amp;quot;Mean edge point: {@m}&amp;quot;;
my @vs = |&amp;amp;finder.nearest(@m, 2, prop =&amp;gt; &amp;lt;label&amp;gt;).flat;
say &amp;quot;To remove: {@vs}&amp;quot;;

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Mean edge point: -2.5980762113536224 -0.5
# To remove: w3 w6

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Loop over all maze edges, removing wall-maze edges:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $g4 = $g1.clone;
for $mazePath.edges -&amp;gt; $e {
    my @points = $g2.vertex-coordinates{($e.kv)};
    my @m = |((@points.head &amp;lt;&amp;lt;+&amp;gt;&amp;gt; @points.tail) &amp;gt;&amp;gt;/&amp;gt;&amp;gt; 2);
    my @vs = |&amp;amp;finder.nearest(@m, 2, prop =&amp;gt; &amp;lt;label&amp;gt;).flat;
    $g4 = $g4.edge-delete(@vs.head =&amp;gt; @vs.tail);
}

$g4

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 544, edges =&amp;gt; 544, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;The start and end points of the maze:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my ($start, $end) = $g4.vertex-list.head, $g4.vertex-list.sort({ $_.substr(1).Int }).tail;

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# (w0 w543)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Finding the Maze Solution:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
my $solution = Graph::Path.new: $mazePath.find-shortest-path(|$mazePath.vertex-list.sort(*.Int)&amp;#91;0,*-1]);
$solution.vertex-coordinates = $mazePath.vertex-coordinates.grep({$_.key ∈ $solution.vertex-list }).Hash;

$solution

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Graph(vertexes =&amp;gt; 50, edges =&amp;gt; 49, directed =&amp;gt; False)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Plot the maze:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: perl; title: ; notranslate"&gt;
#% html

my @mazeStartEnd = $start, $end, |$g4.neighborhood-graph(&amp;#91;$start, $end]).edges;

my $g5 = $g4.union($solution);

my %opts = 
    :!node-labels,
    background =&amp;gt; &amp;quot;#1F1F1F&amp;quot;,
    node-width =&amp;gt; 0.8,
    node-height =&amp;gt; 0.8,
    node-shape =&amp;gt; &amp;#039;circle&amp;#039;,
    edge-width =&amp;gt; 40,
    size =&amp;gt; &amp;#039;10,10!&amp;#039;,
    engine =&amp;gt; &amp;#039;neato&amp;#039;;

$g4.dot(highlight =&amp;gt; {&amp;#039;#1F1F1F&amp;#039; =&amp;gt; @mazeStartEnd}, |%opts):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4793" data-permalink="https://raku-advent.blog/2025/12/24/day-24-maze-making-using-graphs/hexagonal-grid-maze-3/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-3.png" data-orig-size="1171,511" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Hexagonal-grid-maze-3" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-3.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-3.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/hexagonal-grid-maze-3.png" alt="" class="wp-image-4793" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;(&lt;a href="https://raw.githubusercontent.com/antononcube/RakuForPrediction-blog/refs/heads/main/Articles/Diagrams/Maze-making-using-graphs/Hexagonal-grid-maze-4.png"&gt;Here is the solution of the maze&lt;/a&gt;).&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Additional Comments&lt;/h2&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;The initial (and unfinished) version of this document was created 13 months ago.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Its completion was postponed because the blog post&amp;nbsp;&lt;a href="https://raku-advent.blog/2024/12/12/day-12-graphs-in-raku/"&gt;&amp;#8220;Day 12 – Graphs in Raku&amp;#8221;&lt;/a&gt;, [AA1], featured many of the graph operations in &amp;#8220;Graph&amp;#8221;, [AAp1].
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;(Well, until this Raku Advent effort&amp;#8230;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;The document demonstrates how feature-rich the package &amp;#8220;Graph&amp;#8221; is.&lt;/li&gt;



&lt;li&gt;Here are the special graph functionalities used to create the mazes:
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Construction of&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/GridGraph.html"&gt;regular grid graphs&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;Construction of&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/HexagonalGridGraph.html"&gt;hexagonal grid graphs&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;Construction of&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/TriangularGridGraph.html"&gt;triangular grid graphs&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://mathworld.wolfram.com/Subgraph.html"&gt;Subgraph&lt;/a&gt;&amp;nbsp;extraction&lt;/li&gt;



&lt;li&gt;&lt;a href="https://mathworld.wolfram.com/NeighborhoodGraph.html"&gt;Neighborhood graphs&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://mathworld.wolfram.com/GraphDifference.html"&gt;Graph difference&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;Edge deletion&lt;/li&gt;



&lt;li&gt;Graph plotting via Graphviz DOT using:
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Customized styling of various elements&lt;/li&gt;



&lt;li&gt;Vertex coordinates&lt;/li&gt;



&lt;li&gt;Specified vertex labels (see the top of the tree)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Graph highlighting
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Multiple sets of vertices and edges with different colors can be specified&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;References&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Articles, Blog Posts&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AA1] Anton Antonov,&amp;nbsp;&lt;a href="https://raku-advent.blog/2024/12/12/day-12-graphs-in-raku/"&gt;“Day 12 – Graphs in Raku”&lt;/a&gt;, (2024),&amp;nbsp;&lt;a href="https://raku-advent.blog/"&gt;Raku Advent Calendar at WordPress&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Packages&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp1] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Graph"&gt;Graph, Raku package&lt;/a&gt;, (2024–2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp2] Anton Antonov, &lt;a href="https://github.com/antononcube/Raku-Math-Nearest"&gt;Math::Nearest, Raku package&lt;/a&gt;, (2024),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Videos&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAv1] Anton Antonov,&amp;nbsp;&lt;a href="https://www.youtube.com/playlist?list=PLke9UbqjOSOiMnn8kNg6pb3TFWDsqjNTN"&gt;&amp;#8220;Graphs&amp;#8221; videos playlist&lt;/a&gt;, (2024-2025),&amp;nbsp;&lt;a href="https://www.youtube.com/@AAA4prediction"&gt;YouTube/@AAA4prediction&lt;/a&gt;.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This document (notebook) describes three ways of making mazes (or labyrinths) using graphs. The first two are based on rectangular grids; the third on a hexagonal grid.</div>
    </summary>
    <author>
      <name>Anton Antonov Antonov</name>
    </author>
    <id>http://raku-advent.blog/?p=4784</id>
    <published>2025-12-24T02:38:39Z</published>
    <updated>2025-12-24T02:38:39Z</updated>
    <category term="2025"/>
    <category term="Literate programming"/>
    <category term="Modules"/>
    <category term="Advent"/>
    <category term="Graph"/>
    <category term="Graph Theory"/>
    <category term="maze"/>
    <category term="Maze generation"/>
    <category term="Raku"/>
    <category term="rakulang"/>
  </entry>
  <entry>
    <title>Day 23 – A Day Late and A Fish Short</title>
    <link rel="alternate" href="https://raku-advent.blog/2025/12/23/day-23-a-day-late-and-a-fish-short/" type="text/html"/>
    <content type="html">
&lt;p class="wp-block-paragraph"&gt;Hello again! I return during this week of winter solstice to tell you about my experience participating in the &lt;a href="https://langjamgamejam.com/"&gt;Langjam Gamejam&lt;/a&gt;. I planned to use Raku, partially so that you could have an advent blogpost to read today, but also because Raku&amp;#8217;s builtin support for grammars ensure that I would not get stuck when writing my parser.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Preparation&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;I did a few things to ensure that I would be able to complete the game jam. The first was to be realistic about what I could achieve; with seven days of time, I could realistically expect to produce about three weekends worth of working code. This is only going to be a few hundred lines, maybe one or two files total, and prioritizing basic functionality over any fancy features.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I decided to make an idle game.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;There&amp;#8217;s no rule against deciding that ahead of time. I also decided to use Raku. That&amp;#8217;s allowed too. I read the source of a couple different idle games too, mostly to get ideas of what not to do. In particular, big thanks to &lt;a href="https://orteil.dashnet.org/igm/"&gt;Idle Game Maker by Orteil&lt;/a&gt;, &lt;a href="https://ivark.github.io/AntimatterDimensions/"&gt;Antimatter Dimensions by Ivar K.&lt;/a&gt;, and &lt;a href="https://trimps.github.io/"&gt;Trimps by the Trimp authors&lt;/a&gt; for publishing reasonably-readable source code. All three of these have some notion of programmability, although I ended up doing something quite different.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Sunday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;The first place to start when making a game is with the &lt;em&gt;scenario&lt;/em&gt; that the&lt;br&gt;player will be asked to experience. Games are fundamentally about roleplay,&lt;br&gt;and roles only exist within scenarios. Fortunately, I didn&amp;#8217;t have to come up&lt;br&gt;with any of this.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Instead, I asked my friend &lt;a href="https://newrem.com/"&gt;Remi&lt;/a&gt; to come up with something interesting. We spent a couple hours adapting an idea for a &lt;a href="https://zelda.fandom.com/wiki/Fishing"&gt;Zelda-style fishing minigame&lt;/a&gt;, with the novel twist that the game would mechanically be an &lt;a href="https://en.wikipedia.org/wiki/Incremental_game"&gt;idle game&lt;/a&gt;; instead of putting in the athletic effort to retrieve the fish, the player manages a fishing business and delegates the work to employees.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;It&amp;#8217;s important to allow a genuine brainstorm at the beginning of the process.&lt;br&gt;&lt;a href="https://en.wikipedia.org/wiki/Yes,_and_…"&gt;Yes-and&lt;/a&gt; reasoning is essential for developing concepts. At the same time, it was important that we not plan for work that we couldn&amp;#8217;t schedule. Remi committed to drawing a few icons and I committed to carrying out the core of the gamejam objectives:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Design and implement a programming language&lt;/li&gt;



&lt;li&gt;Design and implement a game using that language&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Monday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;The first place to start when making a language is with the &lt;em&gt;objects&lt;/em&gt; of that language. I don&amp;#8217;t mean &lt;a href="https://esolangs.org/wiki/Object-oriented_paradigm"&gt;object-oriented design&lt;/a&gt; but the idea that the language expresses some sort of manipulation of reality. What are we manipulating? How do we manipulate them?&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;At a high level, idle and incremental games are about &lt;a href="https://en.wikipedia.org/wiki/Resource_management"&gt;resource management&lt;/a&gt;. They can also include &lt;a href="https://en.wikipedia.org/wiki/Capacity_planning"&gt;capacity planning&lt;/a&gt;.  Thus, I decided that &lt;em&gt;resources&lt;/em&gt; are the main objects of study. I also needed some way for the player to interact with the game world, and clickable buttons are a traditional way to express idle games. For each button, I&amp;#8217;d thought to have a corresponding &lt;em&gt;action&lt;/em&gt; in the game, which I&amp;#8217;d also express in language.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I also needed to figure out what substrate I&amp;#8217;m going to use. I mean, of course I&amp;#8217;m using Raku, but how deeply do I want to embed the game? At one end, I could imagine &lt;em&gt;compiling&lt;/em&gt; the game into a single &lt;a href="https://en.wikipedia.org/wiki/Binary_blob"&gt;blob&lt;/a&gt; which runs wholly in the end user&amp;#8217;s windowing system or Web browser, so that there&amp;#8217;s nothing of Raku in the end product.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;At the other end, I could imagine &lt;em&gt;shallowly embedding&lt;/em&gt; the game by writing some Raku subroutines and having the game developer write in ordinary Raku. I initially decided to go with the shallowest embedding that would still allow me to use Raku&amp;#8217;s syntax for arithmetic: a Raku sublanguage, or &lt;a href="https://docs.raku.org/language/slangs"&gt;Raku slang&lt;/a&gt;. Technically, a slang&lt;br&gt;is its own programming language, or so I was prepared to argue.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;One open question concerned the passage of time. A resource evolves in time, perhaps growing or shrinking; it also has some invariants in time, particularly identity. What did I actually want to store internally? All hand-coded games devolve into a soup of objects cross-referenced by string-keyed maps, or at least that was the case for a half-dozen idle games that I&amp;#8217;ve looked at. Maybe we can organize all of that into one big string-keyed map?&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Another question is how the game will be experienced. I&amp;#8217;d assumed that it should be possible to put up some simple HTTP server and run it locally. My notes are unclear, but I think that this is around the first time that I took a serious look at &lt;a href="https://raku.land/zef:rawleyfowler/Humming-Bird"&gt;Humming-Bird&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Tuesday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s actually write some code. I started by writing a slang that abused the Raku metamodel. I was inspired by &lt;a href="https://raku.land/zef:raku-community-modules/OO::Actors"&gt;OO::Actors&lt;/a&gt;, which introduces an &lt;code&gt;actor&lt;/code&gt; keyword, as well as the implementation of the standard &lt;code&gt;grammar&lt;/code&gt; keyword. I can just introduce my own &lt;code&gt;resource&lt;/code&gt; and &lt;code&gt;action&lt;/code&gt; keywords which manage some subexpressions, including Raku arithmetic, and that&amp;#8217;ll be my language. To prototype this, I first wrote out a file which I want to be able to load, and then I wrote the parser which handles it. &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Here&amp;#8217;s a snippet from that first prototype:&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;resource fishmonger {
  flavor-text "employee with knives and a booming voice for telling stories";
  eats seafood by 0.017 per second;
  eats bux by 15 per second;
  converts from seafood into bux by 75 per second;
}
action hire-fishmonger {
  flavor-text "employ a fishmonger to sell seafood";
  costs 10 bux;
  pays 1 fishmonger;
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;Several features are very important here. One big deal is that &lt;a href="https://en.wikipedia.org/wiki/Flavor_text"&gt;flavor text&lt;/a&gt; is inalienable from the resources and actions. I was very conflicted about this. Languages like Idle Game Maker are basically enlightened CSS and HTML; they are extremely concerned with presentation details rather than getting to the essential mechanics and handling time.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;At the same time, Remi and I are both big fans of flavor text both for its immersive value as well as for its ability to create a memorable experience. Another important idea here is that &lt;code&gt;costs&lt;/code&gt; and &lt;code&gt;pays&lt;/code&gt; are two distinct attributes in concrete syntax, even though they&amp;#8217;re going to be implemented as the same underlying sort of amount-and-currency pair.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;This syntax is a little heavy. I was imagining that this would be a sort of Ruby or Tcl DSL where each command takes a row of arguments, some of which are literal tokens, and imperatively builds the corresponding resources and actions.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;At this point, the scenario is complete. The game will have a few natural resources, like plankton, fish, and sharks; a conversion from fish to seafood; employees like fishers, fishmongers, and white mages; and an enhancement that white mages apply to fishers. There is no objective; it&amp;#8217;s a &lt;a href="https://en.wikipedia.org/wiki/Population_dynamics"&gt;population-dynamics&lt;/a&gt; sandbox.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Wednesday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;After a day of trying to understand Raku&amp;#8217;s metamodel, I concluded that a slang is the wrong layer of integration. I really wanted to run an input file through a parser in order to build a small nest of &lt;code&gt;Resource&lt;/code&gt; and &lt;code&gt;Action&lt;/code&gt; objects in memory, set up an HTTP server displaying them, and repeatedly take one tick per second, integrating changes over all of those objects.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;This was a &lt;a href="https://en.wikipedia.org/wiki/Zen_and_the_Art_of_Motorcycle_Maintenance#Gumption_traps"&gt;gumption trap&lt;/a&gt; for me; I completely lost motivation for a few hours. In those times, it is essential to allow one&amp;#8217;s emotions to flow in order to move past them, and also essential to rest in order to restore energy.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;After recovering a bit, I cleaned up my repository and thought about what I should do next. I might as well write a proper grammar. What should that language look like? I agonized over this for a few minutes, went through the possibilities of fixity and bracketing, and eventually decided that a nice little &lt;a href="https://en.wikipedia.org/wiki/S-expression"&gt;S-expression&lt;/a&gt; language would work for my needs.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;This did mean that I would need to internalize arithmetic, but I also knew one of the standard cheats of game development: it&amp;#8217;s okay to not implement arithmetic operations which aren&amp;#8217;t actually used. Consider the following snippet:&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;(resource plankton 1e15
    "little crunchy floaty things"
    (growth 0.004 /s)
    (view water-color (if (&amp;lt; .count 1e20) "clear" "cloudy"))
    (view concentration (str (/ .count 2e14)))
)
(action look-at-water-color
    "gaze at the ocean"
    (enables view plankton water-color)
)
(action measure-plankton
    "buy a plankton meter and put it in the water"
    (enables view plankton concentration)
    (costs 10 bux)
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;This is from my prototype. The only arithmetic that&amp;#8217;s required is in the views, which format internal numbers about resources into strings. For those, I have a mini-language which allows the user to specify any arithmetic they want, as long as it&amp;#8217;s either division or less-than comparisons. The formatting language is strongly typed; the parser won&amp;#8217;t allow a non-Boolean operation as an &lt;code&gt;if&lt;/code&gt; conditional, for example.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Some other design decisions stand out. Flavor text is now required. Resources have starting counts, which are also required. Rates always end with &amp;#8220;/s&amp;#8221;, an abbreviation for &amp;#8220;per second&amp;#8221; that is supposed to easily distinguish them from non-rates.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Gumption management requires not just succeeding, but having a feeling of understanding and competence. I probably could have started on the parser that night, but instead I walked to the bar and speedran &lt;a href="https://en.wikipedia.org/wiki/The_Legend_of_Zelda:_A_Link_to_the_Past"&gt;&lt;em&gt;Zelda 3&lt;/em&gt;&lt;/a&gt;, doing any% No Major Glitches and finishing in about two hours and change. Not a superb time, because I grabbed quite a few backups, including an entire extra heart and two bottles; but I didn&amp;#8217;t die. The parser can wait until tomorrow.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Thursday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Parsing an S-expression is really easy, especially when the list of special forms (the words that can legally follow an opening parenthesis) is short. For each special form, we have a rule that parses each of the required components in order, followed by an optional zero-or-more collection of modifiers / attributes / members / components / accessories. The &lt;code&gt;resource&lt;/code&gt; special form from Wednesday is parsed with a rule like:&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    rule thing:sym { '(resource'   &amp;lt;s&amp;gt; * ')' }&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;The parser bottoms out on some very simple tokens. For parsing numbers, we parse a subset of what Raku accepts and then use &lt;code&gt;.Rat&lt;/code&gt; or &lt;code&gt;.Num&lt;/code&gt; methods to convert those strings to live values by reusing Raku&amp;#8217;s parser. I may not have been able to reuse arithmetic but I was certainly able to reuse the numerals!&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    token id { + }
    token s { '"' + '"' }
    token n { + ('.' +)? ('e' +)? }&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;As I wired up the parser, I also set up a Humming-Bird application. I&amp;#8217;m a fan of Ruby&amp;#8217;s Sinatra and Python&amp;#8217;s Flask, so it seemed like Humming-Bird would be a good fit for me. It doesn&amp;#8217;t come with a preferred HTML-emitting library, so I tried a few options. I started with &lt;a href="https://raku.land/zef:2colours/HTML::Tag"&gt;HTML::Tag&lt;/a&gt;, which I had added to the project on either Tuesday or Wednesday, but after a few minutes of practical usage, it became totally unusable due to syntactic zones of ceremony (&lt;a href="https://youtu.be/4jCjDEb9KZI"&gt;Subramaniam&lt;/a&gt;,&lt;a href="https://blog.ploeh.dk/2019/12/16/zone-of-ceremony/"&gt; Seemann&lt;/a&gt;,&lt;a href="https://lobste.rs/s/o3crnz"&gt; myself&lt;/a&gt;): making a fresh HTML tag requires many source characters. I ended up using &lt;a href="https://raku.land/zef:librasteve/HTML::Functional"&gt;HTML::Functional&lt;/a&gt;, which is much lighter-weight but occasionally allows me to misuse &lt;code&gt;Nil&lt;/code&gt; as a string.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I&amp;#8217;m hacking out two roles. I&amp;#8217;m presenting them here in their final versions; initially they didn&amp;#8217;t take any parameters, which was too restrictive. One role is for rendering HTML and the other role is for evolving with each tick.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The &lt;code&gt;%context&lt;/code&gt; is all of the resources and actions, and the &lt;code&gt;$resource&lt;/code&gt; is the resource currently being acted upon. This sort of late-bound approach is technically too flexible for what I&amp;#8217;m building, but I don&amp;#8217;t feel like restricting it.&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    role Render { method html(%context, $resource) { ... } }
    role Evolve { method tick(%context, $resource) {;} }&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;I committed, pushed, and asked Remi for feedback.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Friday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Remi approves! They&amp;#8217;ll make a few cute little icons for some resources. At this point, I stopped and reflected upon what I&amp;#8217;d made so far. Pastafarians typically take Fridays off, and I&amp;#8217;m not about to work when I could rest instead. What works? What doesn&amp;#8217;t work? Where should I spend the rest of my time? What should I have for dinner?&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The parser works. The &lt;code&gt;Resource&lt;/code&gt; and &lt;code&gt;Action&lt;/code&gt; objects operate as nodes of an AST. Exporting the AST as HTML with &lt;code&gt;Render.html()&lt;/code&gt; works. Traversing the AST for a tick with &lt;code&gt;Evolve.tick()&lt;/code&gt; also works. The Nix environment, which Ihaven&amp;#8217;t mentioned yet, also works; I&amp;#8217;m using &lt;a href="https://github.com/direnv/direnv"&gt;direnv&lt;/a&gt; to configure the environment and&lt;br&gt;install Raku packages.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Arithmetic operations don&amp;#8217;t work yet. Actions don&amp;#8217;t actually act on anything. Remi&amp;#8217;s artwork isn&amp;#8217;t visible and I haven&amp;#8217;t split out the CSS yet.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I should spend the rest of my time getting the core mechanics of rendering and evolution to work properly. Easy to say; harder to do.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;For dinner, I&amp;#8217;ll have noodles of some sort, because it&amp;#8217;s Friday. I ended up having spaghetti and meatballs in red sauce.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Before dinner, I went to the bar and speedran &lt;a href="https://en.wikipedia.org/wiki/Super_Mario_Bros."&gt;&lt;em&gt;Mario 1&lt;/em&gt;&lt;/a&gt;. I played for about 90 minutes but I didn&amp;#8217;t finish a single run. On 8-3, the penultimate level, I was repeatedly defeated by a gauntlet of tough enemies.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Saturday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Humming-Bird got in my way a little; it blocks by default and the&lt;br&gt;documentation doesn&amp;#8217;t explain how to fix it. After reading the relevant code,&lt;br&gt;I had to change this line:&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    listen(8080);&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;To have a non-blocking annotation:&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    listen(8080, :no-block);&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;I also explore how to perform ticks in the background. I do find &lt;a href="https://docs.raku.org/type/Supply#method_interval"&gt;&lt;code&gt;Supply.interval&lt;/code&gt;&lt;/a&gt;, but that will let the interpreter exit. Instead, I end up with the following hack:&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    while 1 { sleep 1; $venture.tick };&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;As I wired up operations and fixing display bugs, I became increasingly stressed as my CSS changes aren&amp;#8217;t being applied. By doing some testing, I discovered that the Humming-Bird convenience helper for attaching static directories is not working. I had initially written:&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    static('/static', 'static');&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;But this doesn&amp;#8217;t work, or it had worked on Friday but not on Saturday, or I had somehow mistyped &amp;#8220;static&amp;#8221;, or any of a dozen other impossible considerations. I knew that I can&amp;#8217;t get distracted by this, and I finished up all of the rest of the functionality; the game works, but it&amp;#8217;s not styled and Remi&amp;#8217;s artwork isn&amp;#8217;t visible.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;That&amp;#8217;s the end of the game jam. I produced a language and a game. However, the game doesn&amp;#8217;t display properly and I wouldn&amp;#8217;t consider it to be playable. What a frustration.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Sunday&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;I&amp;#8217;m not done yet! I want to ensure that the release version has Remi&amp;#8217;s artwork displayed. First, I hand-wrote the static routes; these do correctly route the CSS and images.&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;    $router.get('/static/style.css', -&amp;gt; $req, $resp {
        $resp.file('static/style.css');
    });
    $router.get('/static/icons/:icon', -&amp;gt; $req, $resp {
        my $name = $req.param('icon');
        1$name.contains('..') ?? $resp.status(400) !! $resp.file('static/icons/' ~ $name);
    });&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;I found a few holes in our scenario. For example, there&amp;#8217;s no way to see how many Bux the user has. By default, resource amounts are hidden both to keep the UI uncluttered and to provide a sense of mystery; however, for Bux or seafood, we want to give the user precise numbers. Our existing syntax can fully accommodate this! The view is enabled by an action which doesn&amp;#8217;t have any line items (&lt;code&gt;costs&lt;/code&gt; or &lt;code&gt;pays&lt;/code&gt;) and it prints the &lt;code&gt;.count&lt;/code&gt; variable as-is.&lt;/p&gt;



&lt;pre class="wp-block-code has-small-font-size"&gt;&lt;code&gt;(resource bux 1000
    "wireless cash"
    (view cash-on-hand (str .count))
)
(action check-balance
    "become aware of our earnings"
    (enables view bux cash-on-hand)
)&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;With these two fixes, we now have a working interface that allows the scenario to be fully accessed! The new view looks like this:&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img width="751" height="468" data-attachment-id="4699" data-permalink="https://raku-advent.blog/2025/12/23/day-23-a-day-late-and-a-fish-short/blog-stocks-view/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/blog-stocks-view.png" data-orig-size="751,468" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="blog-stocks-view" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/blog-stocks-view.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/blog-stocks-view.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/blog-stocks-view.png?w=751" alt="" class="wp-image-4699" srcset="https://raku-advent.blog/wp-content/uploads/2025/12/blog-stocks-view.png 751w, https://raku-advent.blog/wp-content/uploads/2025/12/blog-stocks-view.png?w=150 150w, https://raku-advent.blog/wp-content/uploads/2025/12/blog-stocks-view.png?w=300 300w" sizes="(max-width: 751px) 100vw, 751px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Finally, I&amp;#8217;m not going to be able to deploy this version as written. I&amp;#8217;ll have to do some reading on production HTTP setups for Raku. When the game loads, it tries to load one image for every visible resource. If more than about five images are requested then the page fails to load. Every action is an HTTP &lt;code&gt;POST&lt;/code&gt; which causes everything to reload again.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;I imagine that this is properly fixed by adding &lt;a href="https://en.wikipedia.org/wiki/HTTP_ETag"&gt;entity tags&lt;/a&gt; to the HTTP backend so that images can be cached. For example, I took the screenshot in the header of this blog post while Firefox was still considering whether it could load the image for plankton; it eventually gives up:&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img width="348" height="447" data-attachment-id="4702" data-permalink="https://raku-advent.blog/2025/12/23/day-23-a-day-late-and-a-fish-short/blog-missing-image/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/blog-missing-image.png" data-orig-size="348,447" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="blog-missing-image" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/blog-missing-image.png?w=234" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/blog-missing-image.png?w=348" src="https://raku-advent.blog/wp-content/uploads/2025/12/blog-missing-image.png?w=348" alt="" class="wp-image-4702" srcset="https://raku-advent.blog/wp-content/uploads/2025/12/blog-missing-image.png 348w, https://raku-advent.blog/wp-content/uploads/2025/12/blog-missing-image.png?w=117 117w, https://raku-advent.blog/wp-content/uploads/2025/12/blog-missing-image.png?w=234 234w" sizes="(max-width: 348px) 100vw, 348px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Every load of the page causes a different set of images to not load. This is an unacceptable game experience.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;Closing thoughts&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;The idea of a declarative idle-game maker is reasonable and it was only a week&amp;#8217;s effort to prototype a basic interpreter which simulates a simple scenario. I think that the biggest time sinks were trying to make a slang instead of a deeper language with a parser, fighting with Humming-Bird, and generally trying to keep code clean. On that last point: I found that cleaning up my code was necessary to let bugs and mistakes become visible.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The game comes out to about three hundred lines of Raku and fewer than one hundred lines of S-expressions. It&amp;#8217;s within my coding budget for sure. I don&amp;#8217;t think that I went for more than I could reasonably accomplish. The entire code is available &lt;a href="https://gist.github.com/MostAwesomeDude/5db135a86f9f412eb337f636aecdd3eb"&gt;in this gist&lt;/a&gt;. Remi quite reasonably doesn&amp;#8217;t want their art uploaded to GitHub, but you can check out more of their work &lt;a href="https://newrem.com/"&gt;at their website&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Have a happy winter solstice and Holiday!&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Hello again! I return during this week of winter solstice to tell you about my experience participating in the Langjam Gamejam. I planned to use Raku, partially so that you could have an advent blogpost to read today, but also because Raku’s builtin support for grammars ensure that I would not get stuck when writing<a class="more-link" href="https://raku-advent.blog/2025/12/23/day-23-a-day-late-and-a-fish-short/">Continue reading <span class="screen-reader-text">"Day 23 – A Day Late and A Fish Short"</span></a></div>
    </summary>
    <author>
      <name>Corbin</name>
    </author>
    <id>http://raku-advent.blog/?p=4693</id>
    <published>2025-12-23T01:00:00Z</published>
    <updated>2025-12-23T01:00:00Z</updated>
    <category term="2025"/>
    <category term="Applications"/>
    <category term="intro"/>
    <category term="Programming techniques"/>
    <category term="Web services"/>
    <category term="Advent"/>
    <category term="games"/>
    <category term="Raku"/>
    <category term="rakulang"/>
  </entry>
  <entry>
    <title>Day 22 – Numerically 2026 Is Unremarkable Yet Happy</title>
    <link rel="alternate" href="https://raku-advent.blog/2025/12/22/day-22-numerically-2026-is-unremarkable-yet-happy/" type="text/html"/>
    <content type="html">
&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Introduction&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;This document (&lt;a href="https://github.com/antononcube/RakuForPrediction-blog/blob/main/Notebooks/Jupyter/Numerically-2026-is-unremarkable-yet-happy.ipynb"&gt;notebook&lt;/a&gt;) discusses number theory properties and relationships of the integer 2026.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The integer&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;is semiprime and a happy number, with 365 as one of its primitive roots. Although&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;may not be particularly noteworthy in number theory, this provides a great excuse to create various elaborate visualizations that reveal some interesting aspects of the number.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The computations in this document are done with the Raku package &amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/Math::NumberTheory"&gt;&amp;#8220;Math::NumberTheory&amp;#8221;&lt;/a&gt;, [AAp1].&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Setup&lt;/h2&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
use Math::NumberTheory;
use Math::NumberTheory::Utilities;

use Data::Importers;
use Data::Translators;
use Data::TypeSystem;

use Graph;
use Graph::Classes;
use JavaScript::D3;

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Notebook priming code:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#%javascript
require.config({
     paths: {
     d3: 'https://d3js.org/d3.v7.min'
}});

require(&amp;#91;'d3'], function(d3) {
     console.log(d3);
});

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;2026 Is a Happy Semiprime with Primitive Roots&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;First, 2026 is obviously not prime—it is divisible by&amp;nbsp;&lt;code&gt;2&lt;/code&gt;—but dividing it by&amp;nbsp;&lt;code&gt;2&lt;/code&gt;&amp;nbsp;gives a prime,&amp;nbsp;&lt;code&gt;1013&lt;/code&gt;:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
is-prime(2026 / 2)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# True

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Hence,&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;is a&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Semiprime"&gt;&lt;strong&gt;semiprime&lt;/strong&gt;&lt;/a&gt;. The integer&amp;nbsp;&lt;code&gt;1013&lt;/code&gt;&amp;nbsp;is not a&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Gaussian_integer#Gaussian_primes"&gt;Gaussian prime&lt;/a&gt;, though:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
is-prime(1013, :gaussian-integers)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# False

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;A&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Happy_number"&gt;&lt;strong&gt;happy number&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;is a number for which iteratively summing the squares of its digits eventually reaches 1 (e.g., 13 → 10 → 1).&lt;br&gt;Here is a check that&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;is happy:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
is-happy-number(2026)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# True

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here is the corresponding trail of digit-square sums:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
is-happy-number(2026, :trail).tail.head(*-1).join(' → ')

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# 2026 → 44 → 32 → 13 → 10 → 1

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Not many years in this century are happy numbers:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
(2000...2100).grep({ is-happy-number($_) })

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# (2003 2008 2019 2026 2030 2036 2039 2062 2063 2080 2091 2093)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;The decomposition of&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;as&amp;nbsp;&lt;code&gt;2 * 1013&lt;/code&gt;&amp;nbsp;means the multiplicative group modulo&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;has primitive roots. A primitive root exists for an integer &lt;em&gt;n&lt;/em&gt; if and only if &lt;em&gt;n&lt;/em&gt; is &lt;em&gt;1, 2, 4&lt;/em&gt;, &lt;em&gt;p^k&lt;/em&gt;, or &lt;em&gt;2 p^k&lt;/em&gt;, where &lt;em&gt;p&lt;/em&gt; is an odd prime and &lt;em&gt;k &amp;gt; 0&lt;/em&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;We can check additional facts about 2026, such as whether it is&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/Squarefree.html"&gt;&amp;#8220;square-free&amp;#8221;&lt;/a&gt;, among other properties. However, let us compare these with the&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/2025/01/03/numeric-properties-of-2025/"&gt;feature-rich 2025&lt;/a&gt;&amp;nbsp;in the next section.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Comparison with 2025&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here is a side-by-side comparison of key number theory properties for&amp;nbsp;&lt;code&gt;2025&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;.&lt;/p&gt;



&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Property&lt;/th&gt;&lt;th&gt;2025&lt;/th&gt;&lt;th&gt;2026&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Prime or Composite&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Composite&lt;/td&gt;&lt;td&gt;Composite&lt;/td&gt;&lt;td&gt;Both non-prime.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Prime Factorization&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;3⁴ × 5² (81 × 25)&lt;/td&gt;&lt;td&gt;2 × 1013&lt;/td&gt;&lt;td&gt;2025 has repeated small primes; 2026 is a&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Semiprime"&gt;semiprime&lt;/a&gt;&amp;nbsp;(product of two distinct primes).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Number of Divisors&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;15 (highly composite for its size)&lt;/td&gt;&lt;td&gt;4 (1, 2, 1013, 2026)&lt;/td&gt;&lt;td&gt;2025 has many divisors; 2026 has very few.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Perfect Square&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Yes (45² = 2025)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Major highlight for 2025—rare square year.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Sum of Cubes&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Yes (1³ + 2³ + &amp;#8230; + 9³ = (1 + &amp;#8230; + 9)² = 2025)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Iconic property for 2025 (&lt;a href="https://en.wikipedia.org/wiki/Squared_triangular_number"&gt;Nicomachus&amp;#8217;s theorem&lt;/a&gt;).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Happy Number&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;No (process leads to cycle including 4)&lt;/td&gt;&lt;td&gt;Yes (repeated squared digit sums reach 1)&lt;/td&gt;&lt;td&gt;Key point for 2026—its main &amp;#8220;happy&amp;#8221; trait.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Harshad Number&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Yes (divisible by 9)&lt;/td&gt;&lt;td&gt;No (not divisible by 10)&lt;/td&gt;&lt;td&gt;2025 qualifies; 2026 does not.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Primitive Roots&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;This is a relatively rare property to have.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Other Notable Traits&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&amp;#8211; (20 + 25)² = 2025&lt;br&gt;&amp;#8211; Sum of first 45 odd numbers&lt;br&gt;&amp;#8211; Deficient number&lt;br&gt;&amp;#8211; Many pattern-based representations&lt;/td&gt;&lt;td&gt;&amp;#8211; Even number&lt;br&gt;&amp;#8211; Deficient number&lt;br&gt;&amp;#8211; Few special patterns&lt;/td&gt;&lt;td&gt;2025 is packed with elegant properties; 2026 is more &amp;#8220;plain&amp;#8221; beyond being happy.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Overall &amp;#8220;Interest&amp;#8221; Level&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Highly interesting—celebrated in math communities for squares, cubes, and patterns&lt;/td&gt;&lt;td&gt;Relatively uninteresting—basic semiprime with no standout geometric or sum properties&lt;/td&gt;&lt;td&gt;Reinforces blog&amp;#8217;s angle.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;To summarize:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;strong&gt;2025&lt;/strong&gt;&amp;nbsp;stands out as a mathematically rich number, often highlighted in puzzles and articles for its perfect square status and connections to sums of cubes and odd numbers.&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;2026&lt;/strong&gt;, in contrast, has fewer flashy properties &amp;#8212; it&amp;#8217;s a straightforward even semiprime &amp;#8212; but it qualifies as a&amp;nbsp;&lt;em&gt;happy number&lt;/em&gt;&amp;nbsp;and it has a primitive root.&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;Here is a computationally generated comparison table of most of the properties found in the table above:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% html
my &amp;amp;divisors-count = { divisors($_).elems };
&amp;lt;is-prime is-composite divisors-count prime-omega euler-phi is-square-free is-happy-number is-harshad-number is-deficient-number primitive-root&amp;gt;.map({ %(sub =&amp;gt; $_, '2025' =&amp;gt; ::("&amp;amp;$_")(2025), '2026' =&amp;gt; ::("&amp;amp;$_")(2026) ) })
==&amp;gt; to-html(field-names =&amp;gt; &amp;#91;'sub', '2025', '2026'], align =&amp;gt; 'left')

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-table"&gt;&lt;table class="has-fixed-layout"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;sub&lt;/th&gt;&lt;th&gt;2025&lt;/th&gt;&lt;th&gt;2026&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;is-prime&lt;/td&gt;&lt;td&gt;False&lt;/td&gt;&lt;td&gt;False&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;is-composite&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;divisors-count&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;prime-omega&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;euler-phi&lt;/td&gt;&lt;td&gt;1080&lt;/td&gt;&lt;td&gt;1012&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;is-square-free&lt;/td&gt;&lt;td&gt;False&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;is-happy-number&lt;/td&gt;&lt;td&gt;False&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;is-harshad-number&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;td&gt;False&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;is-deficient-number&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;td&gt;True&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;primitive-root&lt;/td&gt;&lt;td&gt;(Any)&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Phi Number System&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Digits of 2026 represented in the&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/PhiNumberSystem.html"&gt;Phi number system&lt;/a&gt;:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @res = phi-number-system(2026);

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# &amp;#91;15 13 10 6 -6 -11 -16]

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Verification:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
@res.map({ ϕ ** $_ }).sum.round(10e-11);

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# 2026

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Happy Numbers Trail Graph&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Let us create and plot a graph showing the trails of all happy numbers less than or equal to 2026. Below, we identify these numbers and their corresponding trails:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @ns = 1...2026;

my @trails = @ns.map({ is-happy-number($_):trail }).grep(*.head);

deduce-type(@trails)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Vector((Any), 302)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here is the corresponding trails graph, highlighting the primes and happy numbers:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% html
my @prime-too = @trails.grep(*.head).map(*.tail.head).grep(*.&amp;amp;is-prime);
my @happy-too = @ns.grep(*.&amp;amp;is-harshad-number).grep(*.&amp;amp;is-happy-number);

my %highlight = '#006400' =&amp;gt; @prime-too».Str,    # Deep Christmas green for primes
                'Blue' =&amp;gt; &amp;#91;2026.Str, ],            # Blue for the special year
                '#fbb606ff' =&amp;gt; @happy-too».Str;  # Darker gold for joyful numbers

my @edges = @trails.map({ $_.tail.head(*-1).rotor(2 =&amp;gt; -1).map({ $_.head.Str =&amp;gt; $_.tail.Str }) }).flat;

my $gTrails = Graph.new(@edges):!directed;

$gTrails.dot(
    engine =&amp;gt; 'neato', 
    graph-size =&amp;gt; 12, 
    vertex-shape =&amp;gt; 'ellipse', vertex-height =&amp;gt; 0.2, vertex-width =&amp;gt; 0.4,
    :10vertex-font-size,
    vertex-color =&amp;gt; '#B41E3A',
    vertex-fill-color =&amp;gt; '#B41E3A',
    arrowsize =&amp;gt; 0.6,
    edge-color =&amp;gt; '#B41E3A',
    edge-width =&amp;gt; 1.4,
    splines =&amp;gt; 'curved',
    :%highlight
):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;a href="https://raw.githubusercontent.com/antononcube/RakuForPrediction-blog/b514cb479c3789f95b4b7c3c5325f0987514f28e/Articles/Diagrams/Numerically-2026-is-unremarkable-yet-happy/Happy-number-trails-upto-2026-graph.svg" target="_blank" rel=" noreferrer noopener"&gt;&lt;img data-attachment-id="4654" data-permalink="https://raku-advent.blog/2025/12/22/day-22-numerically-2026-is-unremarkable-yet-happy/happy-number-trails-upto-2026-graph/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/happy-number-trails-upto-2026-graph.png" data-orig-size="1152,1082" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Happy-number-trails-upto-2026-graph" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/happy-number-trails-upto-2026-graph.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/happy-number-trails-upto-2026-graph.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/happy-number-trails-upto-2026-graph.png" alt="" class="wp-image-4654" /&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Triangular Numbers&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;There is a theorem by Gauss stating that any integer can be represented as a sum of at most three triangular numbers. Instead of programming such an integer decomposition representation in Raku, we can simply use&amp;nbsp;&lt;a href="https://www.wolframalpha.com/"&gt;Wolfram|Alpha&lt;/a&gt;, [AA1, AA3], or&amp;nbsp;&lt;a href="https://www.wolfram.com/wolframscript/"&gt;&lt;code&gt;wolframscript&lt;/code&gt;&lt;/a&gt;&amp;nbsp;to find an &amp;#8220;interesting&amp;#8221; solution:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% bash
wolframscript -code 'FindInstance&amp;#91;{2026 == PolygonalNumber&amp;#91;i] + PolygonalNumber&amp;#91;j] + PolygonalNumber&amp;#91;k], i &amp;gt; 10, j &amp;gt; 10, k &amp;gt; 10}, {i, j, k}, Integers]'

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# {{i -&amp;gt; 11, j -&amp;gt; 19, k -&amp;gt; 59}}

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here, we verify the result using Raku:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
say "Triangular numbers : ", &amp;lt;11 19 59&amp;gt;.&amp;amp;polygonal-number(:3sides);
say "Sum : ", &amp;lt;11 19 59&amp;gt;.&amp;amp;polygonal-number(:3sides).sum;

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Triangular numbers : (66 190 1770)
# Sum : 2026

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Chord Diagrams&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here is the number of primitive roots of the&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/ModuloMultiplicationGroup.html"&gt;multiplication group modulo&lt;/a&gt;&amp;nbsp;2026:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
primitive-root-list(2026).elems

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# 440

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here are chord plots [AA2, AAp1, AAp2, AAv1] corresponding to a few selected primitive roots:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% js
my $n = 2026;
&amp;lt;339 365 1529&amp;gt;.map( -&amp;gt; $p { 
    my &amp;amp;f = -&amp;gt; $x { power-mod($p, $x, $n) =&amp;gt; power-mod($p, $x + 1, $n) };
    
    my @segments = circular-chords-tracing($n, with =&amp;gt; &amp;amp;f, :d);
    
    @segments .= map({ $_&amp;lt;group&amp;gt; = $_&amp;lt;group&amp;gt;.Str; $_ });
    
    js-d3-list-line-plot(
        @segments,
        stroke-width =&amp;gt; 0.1,
        background =&amp;gt; '#1F1F1F',
        :300width, :300height,
        :!axes,
        :!legends,
        :10margins,
        color-scheme =&amp;gt; 'Ivory',
        #:$title-color, title =&amp;gt; $p
        )
}).join("\n")

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image size-large"&gt;&lt;a href="https://raw.githubusercontent.com/antononcube/RakuForPrediction-blog/refs/heads/main/Articles/Diagrams/Numerically-2026-is-unremarkable-yet-happy/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png" target="_blank" rel=" noreferrer noopener"&gt;&lt;img loading="lazy" width="1024" height="340" data-attachment-id="4649" data-permalink="https://raku-advent.blog/2025/12/22/day-22-numerically-2026-is-unremarkable-yet-happy/2026-primitive-root-chord-plots-for-339-365-1529-light-black/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png" data-orig-size="1433,476" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="2026-primitive-root-chord-plots-for-339-365-1529-light-black" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png?w=750" src="https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png?w=1024" alt="" class="wp-image-4649" srcset="https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png?w=1024 1024w, https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png?w=150 150w, https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png?w=300 300w, https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png?w=768 768w, https://raku-advent.blog/wp-content/uploads/2025/12/2026-primitive-root-chord-plots-for-339-365-1529-light-black.png 1433w" sizes="(max-width: 1024px) 100vw, 1024px" /&gt;&lt;/a&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;It is interesting that 365 (the number of days in a common calendar year) is a primitive root of the multiplicative group generated by&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;. Not many years have this property this century; many do not have primitive roots at all.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
(2000...2100).hyper(:4degree).grep({ 365 ∈ primitive-root-list($_) })

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# (2003 2026 2039 2053 2063 2078 2089)

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;&lt;a href="https://mathworld.wolfram.com/QuarticGraph.html"&gt;Quartic Graphs&lt;/a&gt;&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;The number&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;appears in&amp;nbsp;&lt;a href="https://oeis.org/search?q=2026&amp;amp;fmt=data"&gt;18 results of the search &amp;#8220;2026 graphs&amp;#8221;&lt;/a&gt;&amp;nbsp;in&amp;nbsp;&lt;a href="https://oeis.org/"&gt;«The On-line Encyclopedia of Integer Sequences»&lt;/a&gt;. Here is the first result (from 2025-12-17):&amp;nbsp;&lt;a href="https://oeis.org/A033483"&gt;A033483&lt;/a&gt;, &amp;#8220;Number of disconnected 4-valent (or quartic) graphs with n nodes.&amp;#8221; Below, we ingest the internal format of A033483&amp;#8217;s page:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $internal = data-import('https://oeis.org/A033483/internal', 'plaintext');
text-stats($internal)

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# (chars =&amp;gt; 2928 words =&amp;gt; 383 lines =&amp;gt; 98)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here, we verify the title:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
with $internal.match(/ '%' N (&amp;lt;-&amp;#91;%]&amp;gt;*)? &amp;lt;?before '%'&amp;gt; /) { $0.Str.trim }

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Number of disconnected 4-valent (or quartic) graphs with n nodes.

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here, we get the corresponding sequence:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @seq = do with data-import('https://oeis.org/A033483/list', 'plaintext').match(/'&amp;#91;' (.*) ']'/) {
    $0.Str.split(',')».trim
}

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# &amp;#91;0 0 0 0 0 0 0 0 0 0 1 1 3 8 25 88 378 2026 13351 104595 930586 9124662 96699987 1095469608 13175272208 167460699184 2241578965849 31510542635443 464047929509794 7143991172244290 114749135506381940 1919658575933845129 33393712487076999918 603152722419661386031]

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Here we find the position of&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;&amp;nbsp;in that sequence:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
@seq.grep(2026):k

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# (17)

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;Given the title of the sequence and the extracted position of&amp;nbsp;&lt;code&gt;2026&lt;/code&gt;, this means that the number of disconnected&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/QuarticGraph.html"&gt;4-regular graphs&lt;/a&gt;&amp;nbsp;with 17 vertices is 2026. Let us create a few graphs from that set by using the&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/CompleteGraph.html"&gt;5-vertex complete graph (K₅)&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="//path?"&gt;circulant graphs&lt;/a&gt;.&lt;br&gt;Here is an example of such a graph:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% html
reduce(    
    { $^a.union($^b) },
    &amp;#91;
        Graph::Complete.new(5),
        Graph::Complete.new(5).index-graph(6),
        Graph::Circulant.new(7,&amp;#91;1,2]).index-graph(11)
    ]
).dot(engine =&amp;gt; 'neato'):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4652" data-permalink="https://raku-advent.blog/2025/12/22/day-22-numerically-2026-is-unremarkable-yet-happy/quartic-graph-1-light/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-1-light.png" data-orig-size="425,447" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Quartic-graph-1-light" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-1-light.png?w=285" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-1-light.png?w=425" src="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-1-light.png" alt="" class="wp-image-4652" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;And here is another one:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#% html
my $g = reduce(    
    { $^a.union($^b) },
    &amp;#91;
        Graph::Complete.new(5).index-graph(13),
        Graph::Circulant.new(12, &amp;#91;1, 5]).index-graph(1),
    ]
);
$g.dot(engine =&amp;gt; 'neato', splines =&amp;gt; 'curved'):svg

&lt;/pre&gt;&lt;/div&gt;


&lt;figure class="wp-block-image"&gt;&lt;img data-attachment-id="4653" data-permalink="https://raku-advent.blog/2025/12/22/day-22-numerically-2026-is-unremarkable-yet-happy/quartic-graph-2-light/" data-orig-file="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-2-light.png" data-orig-size="484,420" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Quartic-graph-2-light" data-image-description="" data-image-caption="" data-medium-file="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-2-light.png?w=300" data-large-file="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-2-light.png?w=484" src="https://raku-advent.blog/wp-content/uploads/2025/12/quartic-graph-2-light.png" alt="" class="wp-image-4653" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Here, we check that all vertices have degree 4:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
$g.vertex-degree.sum / $g.vertex-count

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# 4

&lt;/pre&gt;&lt;/div&gt;


&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Remark:&lt;/strong&gt;&amp;nbsp;Note that although the plots show disjoint graphs, each graph plot represents a single graph object.&lt;/p&gt;



&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;Ways to compute 2026&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here are a few ways to compute 2026:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
sub postfix:&amp;lt;!&amp;gt;(UInt:D $n) { &amp;#91;*] 1..$n }

&amp;#91; 
    2**11 - 22,
    1 + 2 * 3 / 4 / 5 / 6 * 7! * 8 + 9,
    1 + 2 + 3 * 4! + 5 / 6! * 7 * 8! - 9,
    1 + 2 + 345 * 6 - 7 * 8 + 9,
    1 - 2 * 3! * 456 * 7 + 8! + 9,
    12 / 3! * 4**5 + 67 - 89,
    12**3 + 45 / 6! * 7! - 8 - 9,
    123 / 4! * 56 * 7 + 8 + 9,
    9! / 8 / 7 / 6 + 5**4 + 321,  
    9 * 8 - 7 + 654 * 3 - 2 + 1,
    987 + 6! + 5 * 4**3 - 2 + 1
]

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# &amp;#91;2026 2026 2026 2026 2026 2026 2026 2026 2026 2026 2026]

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Additional Comments&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;This section has a few additional (leftover) comments.&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;After I researched and published the blog post&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/2025/01/03/numeric-properties-of-2025/"&gt;&amp;#8220;Numeric properties of 2025&amp;#8221;&lt;/a&gt;, [AA1], in the first few days of 2025, I decided to program additional&amp;nbsp;&lt;a href="https://www.youtube.com/playlist?list=PLke9UbqjOSOhUx2m-ObMq42XEsBWtHWzN"&gt;Number theory functionalities for Raku&lt;/a&gt;&amp;nbsp;&amp;#8212; see the package&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/Math::NumberTheory"&gt;&amp;#8220;Math::NumberTheory&amp;#8221;&lt;/a&gt;, [AAp1].&lt;/li&gt;



&lt;li&gt;Most notably, &amp;#8220;Math::NumberTheory&amp;#8221; is extended to work with&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Gaussian_integer"&gt;Gaussian integers&lt;/a&gt;, and the operators&amp;nbsp;&lt;code&gt;GCD&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;LCD&lt;/code&gt;&amp;nbsp;are also extended to work with rationals.&lt;/li&gt;



&lt;li&gt;One of my current goals is to make Raku&amp;nbsp;&lt;em&gt;&lt;strong&gt;extremely good&lt;/strong&gt;&lt;/em&gt;&amp;nbsp;for researching Number theory phenomena.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;One of the most significant features of Raku is its bignum arithmetic and its good built-in numeric functions applicable in Number theory.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Number theory provides many opportunities for visualizations, so I included utilities for some of the popular patterns in &amp;#8220;Math::NumberTheory&amp;#8221;, [AAp1, AAp2].
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;I use the package&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/JavaScript::D3"&gt;&amp;#8220;JavaScript::D3&amp;#8221;&lt;/a&gt;, [AAp3], for almost all Number theory visualizations with Raku.&lt;/li&gt;



&lt;li&gt;Often, I visualize associated graphs using the DOT language specs provided by the package&amp;nbsp;&lt;a href="https://raku.land/zef:antononcube/Graph"&gt;&amp;#8220;Graph&amp;#8221;&lt;/a&gt;, [AAp4] (as seen above).
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;The&amp;nbsp;&lt;a href="https://graphviz.org/download/"&gt;Graphviz engines&lt;/a&gt;&amp;nbsp;generate images in different formats using&amp;nbsp;&lt;a href="https://graphviz.org/doc/info/lang.html"&gt;DOT&lt;/a&gt;&amp;nbsp;specs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;The number of years in this century that have primitive roots and have 365 as a primitive root is less than the number of years that are happy numbers.&lt;/li&gt;



&lt;li&gt;I would say I spent too much time finding a good, suitable, Christmas-themed combination of colors for the trails graph.&lt;/li&gt;



&lt;li&gt;To get the quartic graph counting sequence&amp;nbsp;&lt;a href="https://oeis.org/A033483"&gt;A033483&lt;/a&gt;, I tried to use&amp;nbsp;&lt;a href="https://raku.land/zef:raku-community-modules/Math::Sequences"&gt;&amp;#8220;Math::Sequences&amp;#8221;&lt;/a&gt;, but since that package does not provide the sequence, I used an ad hoc retrieval (for which Raku is perfect.)&lt;/li&gt;



&lt;li&gt;While working on this document, I implemented in &amp;#8220;Math::NumberTheory&amp;#8221; a set of new functions:&amp;nbsp;&lt;code&gt;integer-digits&lt;/code&gt;,&amp;nbsp;&lt;code&gt;is-happy-number&lt;/code&gt;,&amp;nbsp;&lt;code&gt;is-harshad-number&lt;/code&gt;,&amp;nbsp;&lt;code&gt;is-abundant-number&lt;/code&gt;,&amp;nbsp;&lt;code&gt;is-perfect-number&lt;/code&gt;,&amp;nbsp;&lt;code&gt;is-deficient-number&lt;/code&gt;,&amp;nbsp;&lt;code&gt;abundant-number&lt;/code&gt;,&amp;nbsp;&lt;code&gt;deficient-number&lt;/code&gt;, and&amp;nbsp;&lt;code&gt;perfect-number&lt;/code&gt;.
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;All of these functions &amp;#8212; except&amp;nbsp;&lt;code&gt;integer-digits&lt;/code&gt;&amp;nbsp;&amp;#8212; had lower implementation priority.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;Another implementation effort was to finally come up with a Command Line Interface (CLI).
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;I advocate that a CLI should be considered for&amp;nbsp;&lt;em&gt;all&lt;/em&gt;&amp;nbsp;Raku packages, and&amp;nbsp;&lt;em&gt;most&lt;/em&gt;&amp;nbsp;should have one.&lt;br&gt;&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#%bash
number-theory is happy number 2026

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# True

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
#%bash
number-theory primitive root list 2026 | grep 365

&lt;/pre&gt;&lt;/div&gt;

&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# 365

&lt;/pre&gt;&lt;/div&gt;


&lt;hr class="wp-block-separator has-alpha-channel-opacity" /&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;References&lt;/h2&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Articles, blog posts&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AA1] Anton Antonov,&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/2025/01/03/numeric-properties-of-2025/"&gt;&amp;#8220;Numeric properties of 2025&amp;#8221;&lt;/a&gt;, (2025),&amp;nbsp;&lt;a href="https://mathematicaforprediction.wordpress.com/"&gt;RakuForPrediction at WordPress&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AA2] Anton Antonov,&amp;nbsp;&lt;a href="https://mathematicaforprediction.wordpress.com/2025/04/08/primitive-roots-generation-trails/"&gt;&amp;#8220;Primitive roots generation trails&amp;#8221;&lt;/a&gt;, (2025),&amp;nbsp;&lt;a href="https://mathematicaforprediction.wordpress.com/"&gt;MathematicaForPrediction at WordPress&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AA3] Anton Antonov,&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/2024/05/18/chatbook-new-magic-cells/"&gt;“Chatbook New Magic Cells”&lt;/a&gt;, (2024),&amp;nbsp;&lt;a href="https://rakuforprediction.wordpress.com/"&gt;RakuForPrediction at WordPress&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[EW1] Eric W. Weisstein,&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/QuarticGraph.html"&gt;&amp;#8220;Quartic Graph&amp;#8221;&lt;/a&gt;. From&amp;nbsp;&lt;a href="https://mathworld.wolfram.com/"&gt;MathWorld&amp;#8211;A Wolfram Resource&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Notebooks&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAn1] Anton Antonov,&amp;nbsp;&lt;a href="https://community.wolfram.com/groups/-/m/t/3442027"&gt;&amp;#8220;Primitive roots generation trails&amp;#8221;&lt;/a&gt;, (2025),&amp;nbsp;&lt;a href="https://community.wolfram.com/"&gt;Wolfram Community&lt;/a&gt;. STAFFPICKS, April 9, 2025​.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[EPn1] Ed Pegg,&amp;nbsp;&lt;a href="https://community.wolfram.com/groups/-/m/t/3347182"&gt;“Happy 2025 =1³+2³+3³+4³+5³+6³+7³+8³+9³!”&lt;/a&gt;,&amp;nbsp;&lt;a href="https://community.wolfram.com/"&gt;​Wolfram Community&lt;/a&gt;, STAFFPICKS, December 30, 2024​.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Packages, paclets&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp1] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Math-NumberTheory"&gt;Math::NumberTheory, Raku package&lt;/a&gt;, (2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp2] Anton Antonov,&lt;br&gt;&lt;a href="https://resources.wolframcloud.com/PacletRepository/resources/AntonAntonov/NumberTheoryUtilities/"&gt;NumberTheoryUtilities, Wolfram Language paclet&lt;/a&gt;, (2025),&amp;nbsp;&lt;a href="https://resources.wolframcloud.com/PacletRepository"&gt;Wolfram Language Paclet Repository&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp3] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-JavaScript-D3"&gt;JavaScript::D3, Raku package&lt;/a&gt;, (2021-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;[AAp4] Anton Antonov,&amp;nbsp;&lt;a href="https://github.com/antononcube/Raku-Graph"&gt;Graph, Raku package&lt;/a&gt;, (2024-2025),&amp;nbsp;&lt;a href="https://github.com/antononcube"&gt;GitHub/antononcube&lt;/a&gt;.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a&gt;&lt;/a&gt;Videos&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;[AAv1] Anton Antonov,&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=6uCIoonlybk"&gt;Number theory neat examples in Raku (Set 3)&lt;/a&gt;, (2025),&amp;nbsp;&lt;a href="https://www.youtube.com/@AAA4prediction"&gt;YouTube/@AAA4prediction&lt;/a&gt;.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This document explores the properties and relationships of the integer 2026. It is classified as a semiprime and a happy number, with 365 serving as one of its primitive roots. While 2026 may not stand out significantly in number theory, it offers a great opportunity to create elaborate visualizations that highlight some interesting aspects of the number.</div>
    </summary>
    <author>
      <name>Anton Antonov Antonov</name>
    </author>
    <id>http://raku-advent.blog/?p=4645</id>
    <published>2025-12-22T01:01:00Z</published>
    <updated>2025-12-22T01:01:00Z</updated>
    <category term="2025"/>
    <category term="Literate programming"/>
    <category term="Modules"/>
    <category term="Advent"/>
    <category term="Graphs"/>
    <category term="Number Theory"/>
    <category term="Primitive roots"/>
    <category term="Raku"/>
    <category term="rakulang"/>
  </entry>
  <entry>
    <title> Rakudo compiler, Release #188 (2025.12)</title>
    <link rel="alternate" href="https://rakudo.org/post/announce-rakudo-release-2025.12" type="text/html"/>
    <id>https://rakudo.org/post/announce-rakudo-release-2025.12</id>
    <published>2025-12-20T00:00:00Z</published>
    <updated>2025-12-20T00:00:00Z</updated>
  </entry>
  <entry>
    <title> Rakudo compiler, Release #187 (2025.11)</title>
    <link rel="alternate" href="https://rakudo.org/post/announce-rakudo-release-2025.11" type="text/html"/>
    <id>https://rakudo.org/post/announce-rakudo-release-2025.11</id>
    <published>2025-11-15T00:00:00Z</published>
    <updated>2025-11-15T00:00:00Z</updated>
  </entry>
  <entry>
    <title>Crolite: filling the "Mojolicious::Lite" gap in the Cro ecosystem</title>
    <link rel="alternate" href="https://dev.to/fco/crolite-filling-the-mojoliciouslite-gap-in-the-cro-ecosystem-4ebi" type="text/html"/>
    <content type="html">&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When I start something new in Raku with Cro, I almost always begin with a mental sketch: two or three routes, a response shape, maybe a typed segment. In the Perl world I leaned heavily on &lt;code&gt;Mojolicious::Lite&lt;/code&gt; for that prototyping phase. In Cro—powerful and modular as it is—I missed an immediate &lt;strong&gt;“lite mode”&lt;/strong&gt;: no manual wiring of server, pipeline, and router just to test a thought. Out of that friction came &lt;strong&gt;Crolite&lt;/strong&gt;: a thin layer that re‑exports Cro's routing keywords and adds a multi &lt;code&gt;MAIN&lt;/code&gt; with quick exploration commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Crolite Is
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Goal:&lt;/strong&gt; Make minimal HTTP prototypes trivial while ideas mature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approach:&lt;/strong&gt; Reuse Cro's router directly; no new DSL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deliverable:&lt;/strong&gt; A collected &lt;code&gt;RouteSet&lt;/code&gt; + a tiny embedded CLI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Philosophy:&lt;/strong&gt; “Start now; graduate later to a full Cro app.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;From a local checkout (inside the project directory):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zef &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once published:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zef &lt;span class="nb"&gt;install &lt;/span&gt;Crolite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  First Example
&lt;/h2&gt;

&lt;p&gt;File &lt;code&gt;example.raku&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Crolite;

get -&amp;gt; $any {
    content 'text/plain', "Hello: $any";
}

delete -&amp;gt; 'thing', Int $id {
    content 'application/json', %( :$id );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List derived routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raku example.raku routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run a development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raku example.raku &lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;127.0.0.1 &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000 daemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test a route without a persistent daemon (ephemeral in‑memory request):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raku example.raku GET /thing/42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Suggested Workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sketch routes and response formats.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;raku app.raku routes&lt;/code&gt; to confirm patterns.&lt;/li&gt;
&lt;li&gt;Fire single requests: &lt;code&gt;raku app.raku GET /foo/123&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Iterate until it stabilizes.&lt;/li&gt;
&lt;li&gt;Promote to a full Cro project if you need richer middleware, structured logging, TLS, etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  CLI Options
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;routes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print summary of registered endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[--host=0.0.0.0] [--port=10000] daemon&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start simple Cro server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single in‑memory GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single POST (no custom body)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PUT &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single PUT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DELETE &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single DELETE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--method=&amp;lt;VERB&amp;gt; http &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generic form for any method&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Stop the daemon with &lt;code&gt;Ctrl+C&lt;/code&gt; (SIGINT is trapped for graceful shutdown).&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Segments &amp;amp; Typing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Crolite;

get -&amp;gt; 'greet', Str $name {
    content 'text/plain', "Hi $name!";
}

post -&amp;gt; 'sum', Int $a, Int $b {
    content 'application/json', %( total =&amp;gt; $a + $b );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raku app.raku GET /greet/Ana
raku app.raku POST /sum/2/5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Returning JSON
&lt;/h2&gt;

&lt;p&gt;Just produce a &lt;code&gt;Hash&lt;/code&gt; or &lt;code&gt;Map&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get -&amp;gt; 'status' {
    content 'application/json', %( service =&amp;gt; 'ok', ts =&amp;gt; DateTime.now );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hooks (Before / After)
&lt;/h2&gt;

&lt;p&gt;If you manually add &lt;code&gt;before&lt;/code&gt; or &lt;code&gt;after&lt;/code&gt; handlers to the underlying &lt;code&gt;RouteSet&lt;/code&gt;, Crolite includes them when composing the application for &lt;code&gt;daemon&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Crolite;

$*CRO-ROUTE-SET.before: {
    # Simple logging / auth stub
    proceed;
}

get -&amp;gt; 'ping' { content 'text/plain', 'pong' }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  More Complete Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Crolite;

get -&amp;gt; 'health' {
    content 'application/json', %( ok =&amp;gt; True );
}

put -&amp;gt; 'echo', Str $msg {
    content 'text/plain', $msg.uc;
}

post -&amp;gt; 'calc', Int $x, Int $y {
    content 'application/json', %( sum =&amp;gt; $x + $y, prod =&amp;gt; $x * $y );
}

delete -&amp;gt; 'soft', Int $id {
    content 'application/json', %( deleted =&amp;gt; $id, soft =&amp;gt; True );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quick ping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raku app.raku GET /health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raku app.raku &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4000 daemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ergonomics While Prototyping
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rapid changes:&lt;/strong&gt; Save &amp;amp; re‑run; no auto‑reloader (yet).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspection:&lt;/strong&gt; &lt;code&gt;routes&lt;/code&gt; surfaces path typos immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atomic requests:&lt;/strong&gt; Avoids opening another terminal for &lt;code&gt;curl&lt;/code&gt; just to see a body.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Current Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No structured logging out of the box.&lt;/li&gt;
&lt;li&gt;No built‑in TLS / websockets / streaming presets.&lt;/li&gt;
&lt;li&gt;No hot reload.&lt;/li&gt;
&lt;li&gt;Experimental API (may shift).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Migrate to a Full Cro App
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You need chained middleware (auth, tracing, rate limiting).&lt;/li&gt;
&lt;li&gt;You require richer body parsing / serialization customization.&lt;/li&gt;
&lt;li&gt;You integrate multiple services or supervised components.&lt;/li&gt;
&lt;li&gt;You need observability (metrics, distributed tracing, advanced logs).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Possible Future Roadmap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Optional reload in &lt;code&gt;daemon&lt;/code&gt; mode.&lt;/li&gt;
&lt;li&gt;Alternate tabular output for &lt;code&gt;routes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Lightweight latency / metrics helper.&lt;/li&gt;
&lt;li&gt;Test skeleton generator for promotion phase.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Testing Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use the embedded CLI to validate the contract before formal tests.&lt;/li&gt;
&lt;li&gt;When formalizing, reuse &lt;code&gt;Cro::HTTP::Test&lt;/code&gt; (mirrors what the CLI verbs do).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Crolite does not compete with the full flexibility of a structured Cro project; it lowers the &lt;strong&gt;time to first useful response&lt;/strong&gt; when exploring HTTP ideas in Raku. If you also miss the lightness of &lt;code&gt;Mojolicious::Lite&lt;/code&gt;, try making the first step of each spike just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Crolite;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, once the shape hardens, graduate to something more robust.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Suggestions, issues, and PRs welcome.&lt;/em&gt;&lt;/p&gt;

</content>
    <author>
      <name>Fernando Correa de Oliveira</name>
    </author>
    <id>https://dev.to/fco/crolite-filling-the-mojoliciouslite-gap-in-the-cro-ecosystem-4ebi</id>
    <published>2025-09-28T00:28:31Z</published>
    <updated>2025-09-28T00:28:31Z</updated>
    <category term="rakulang"/>
    <category term="cro"/>
    <category term="mojolicious"/>
    <category term="http"/>
  </entry>
  <entry>
    <title>Typed, Named Endpoints for Cro (with HTMX Helpers)</title>
    <link rel="alternate" href="https://dev.to/fco/typed-named-endpoints-for-cro-with-htmx-helpers-g9j" type="text/html"/>
    <content type="html">&lt;p&gt;Cro’s HTTP router is great at declaring routes, but it doesn’t provide a first‑class way to reference those routes elsewhere in your app. Cro::HTTP::RouterUtils fills that gap: it lets you reference endpoints by name, build typed-safe paths, generate HTMX attributes, redirect to routes, and even call the underlying implementation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stable references to routes by name (or auto‑named fallback)&lt;/li&gt;
&lt;li&gt;Typed &lt;code&gt;path()&lt;/code&gt; builder validates parameter types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hx-attrs()&lt;/code&gt; renders HTMX attributes with the correct method and URL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect-to()&lt;/code&gt; returns a Cro redirect to the endpoint&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;call()&lt;/code&gt; invokes the route implementation directly (handy for tests)&lt;/li&gt;
&lt;li&gt;Supports &lt;code&gt;include&lt;/code&gt; with prefixes seamlessly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/FCO/Cro-HTTP-RouterUtils" rel="noopener noreferrer"&gt;https://github.com/FCO/Cro-HTTP-RouterUtils&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zef &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--depsonly&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Cro::HTTP::RouterUtils;

my $app = route {
    # Name a route via a named sub
    get my sub greet-path('greet', $name) {
        content 'text/plain', "Hello, $name!"
    }

    # Use the endpoint by name
    get -&amp;gt; 'links' {
        my $ep = endpoints('greet-path');
        content 'text/html', qq:to/END/
            &amp;lt;a href="{ $ep.path(:name&amp;lt;alice&amp;gt;) }"&amp;gt;alice&amp;lt;/a&amp;gt;
            &amp;lt;a href="#" { $ep.hx-attrs(:name&amp;lt;bob&amp;gt;, :trigger&amp;lt;click&amp;gt;) }&amp;gt;bob&amp;lt;/a&amp;gt;
        END
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Naming and Discovering Endpoints
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Named endpoints: give your route a function name and reference it with &lt;code&gt;endpoints('your-name')&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Auto‑named endpoints: when no name is provided, keys are generated from method and path signature, e.g. &lt;code&gt;get_greet&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Auto-named
get -&amp;gt; 'greet', Str :$name { 200 }
endpoints('get_greet').path;  # =&amp;gt; "/greet"

# Named
get my sub greet-path('greet', $name) { "Hello, $name!" }
endpoints('greet-path').path(:name&amp;lt;alice&amp;gt;);  # =&amp;gt; "/greet/alice"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Includes with prefixes are supported transparently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;include external =&amp;gt; other-routes;   # /external prefix applied

endpoints('external-ep1').method;   # "GET"
endpoints('external-ep1').path;     # "/external/returns-ok"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Typed Path Building
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;path(*%values)&lt;/code&gt; enforces your route’s typed parameters; missing or invalid values throw.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get my sub sum('sum', Int $a, Int $b) { $a + $b }

my $ep = endpoints('sum');
$ep.path(:a(1), :b(2));          # "/sum/1/2"
$ep.path(:a("x"), :b(2));        # throws (type mismatch)
$ep.path(:a(1));                 # throws (missing parameter)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  HTMX Helpers
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;hx-attrs(:args…)&lt;/code&gt; returns a space-separated string of HTMX attributes. It uses the endpoint’s HTTP method by default (e.g., &lt;code&gt;hx-get&lt;/code&gt;) and the built URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="#"
   { endpoints('greet-path').hx-attrs(
       :name&amp;lt;alice&amp;gt;,
       :trigger&amp;lt;click&amp;gt;,
       :target&amp;lt;#out&amp;gt;,
       :swap&amp;lt;'outerHTML settle:200ms'&amp;gt;,
       :push-url&amp;lt;true&amp;gt;,
       :on{ click =&amp;gt; "console.log(\"clicked\")" }
     )
   }&amp;gt;
  Load Alice
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Highlights supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request URL/method: &lt;code&gt;method&lt;/code&gt; override; parameters via &lt;code&gt;:name&amp;lt;...&amp;gt;&lt;/code&gt; etc.&lt;/li&gt;
&lt;li&gt;Core: &lt;code&gt;trigger&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;confirm&lt;/code&gt;, &lt;code&gt;indicator&lt;/code&gt;, &lt;code&gt;swap&lt;/code&gt;, &lt;code&gt;oob&lt;/code&gt; (as &lt;code&gt;hx-swap-oob&lt;/code&gt;), &lt;code&gt;boost&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Navigation: &lt;code&gt;push-url&lt;/code&gt; (Bool|Str), &lt;code&gt;replace-url&lt;/code&gt; (Bool|Str)&lt;/li&gt;
&lt;li&gt;Selection: &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;select-oob&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;JSON: &lt;code&gt;vals&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt;, &lt;code&gt;request&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Flags: &lt;code&gt;disable&lt;/code&gt;, &lt;code&gt;validate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Misc: &lt;code&gt;disabled-elt&lt;/code&gt;, &lt;code&gt;disinherit&lt;/code&gt;, &lt;code&gt;encoding&lt;/code&gt;, &lt;code&gt;ext&lt;/code&gt;, &lt;code&gt;history&lt;/code&gt;, &lt;code&gt;history-elt&lt;/code&gt;, &lt;code&gt;include&lt;/code&gt;, &lt;code&gt;inherit&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, &lt;code&gt;prompt&lt;/code&gt;, &lt;code&gt;sync&lt;/code&gt;, &lt;code&gt;vars&lt;/code&gt; (deprecated)&lt;/li&gt;
&lt;li&gt;Events: &lt;code&gt;:on{ event =&amp;gt; "code" }&lt;/code&gt; emits &lt;code&gt;hx-on:event='code'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example minimal output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hx-get='/greet/alice' hx-trigger='click' hx-target='#out'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Redirects
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get -&amp;gt; 'redir' {
    endpoints('greet-path').redirect-to: :name&amp;lt;ok&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Calling the Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;call(|args)&lt;/code&gt; invokes the underlying route implementation. Literal path segments are auto-injected; you pass only the non-literal parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get my sub ret('ret') { 42 }
get my sub sum('sum', Int $a, Int $b) { $a + $b }

endpoints('ret').call;        # 42
endpoints('sum').call(2, 3);  # 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great for unit tests of pure route logic. If you depend on Cro’s pipeline, prefer &lt;code&gt;Cro::HTTP::Test&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full Example
&lt;/h2&gt;

&lt;p&gt;See &lt;code&gt;examples/example.raku&lt;/code&gt; and &lt;code&gt;examples/ExampleRoute.rakumod&lt;/code&gt; in the repo. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raku examples/example.raku
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then visit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/form&lt;/code&gt; for a classic form&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/links&lt;/code&gt; for &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; links built from endpoints&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/links-htmx&lt;/code&gt; for HTMX-driven links&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Errors and Guarantees
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Unknown endpoint name: throws.&lt;/li&gt;
&lt;li&gt;Missing/invalid path params: throws with a clear message.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;call()&lt;/code&gt; auto-injects literal path segments; you provide the rest.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Isn’t in Cro
&lt;/h2&gt;

&lt;p&gt;Cro focuses on routing and request handling. This utility adds “endpoint as a value” ergonomics—stable references, typed path building, HTMX helpers, and redirect/call helpers—while staying a thin layer on top of &lt;code&gt;Cro::HTTP::Router&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appendix: Include With Prefix Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# examples/ExampleRoute.rakumod
use Cro::HTTP::RouterUtils;

sub other-routes is export {
  route {
    get  my sub external-ep1("returns-ok")  { content "text/plain", "OK" }
    post my sub external-ep2("using-post")  { content "text/plain", "OK" }
  }
}

# elsewhere
include external =&amp;gt; other-routes;
endpoints('external-ep1').path;  # "/external/returns-ok"
endpoints('external-ep2').path;  # "/external/using-post"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;—&lt;br&gt;
Made with Cro::HTTP::RouterUtils (Raku).&lt;/p&gt;

</content>
    <author>
      <name>Fernando Correa de Oliveira</name>
    </author>
    <id>https://dev.to/fco/typed-named-endpoints-for-cro-with-htmx-helpers-g9j</id>
    <published>2025-09-21T22:14:23Z</published>
    <updated>2025-09-21T22:14:23Z</updated>
    <category term="rakulang"/>
    <category term="cro"/>
    <category term="htmx"/>
  </entry>
  <entry>
    <title>HARC Stack: Validating</title>
    <link rel="alternate" href="https://rakujourney.wordpress.com/2025/09/14/harc-stack-validating/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p class="wp-block-paragraph">This is the 15th of the HARC Stack essays. <a href="https://rakujourney.wordpress.com/2025/09/08/harc-stack-dogfooding/">Previous</a> &lt;=</p>



<p class="wp-block-paragraph">Don’t forget – <a href="https://harcstack.org">HARC Stack</a> combines <a href="https://htmx.org">HTMX</a> with raku Air, Red and Cro to supply a fresh approach to web development.</p>



<p class="wp-block-paragraph">Two weeks ago, back before HARC Stack became the darling child of <a href="https://raku.org">https://raku.org</a> fame, we had been <a href="https://rakujourney.wordpress.com/2025/08/10/harc-stack-forming/">Forming</a>. Most of the features of Air::Form were covered in that episode, but Validating was skipped since that is a topic in its own right.</p>



<h2 class="wp-block-heading">Air::Form</h2>



<p class="wp-block-paragraph">Once again, here’s a top level view of the Air::Form code from Air::Examples.</p>



<figure class="wp-block-image size-full is-resized"><img data-attachment-id="1742" data-permalink="https://rakujourney.wordpress.com/2025/08/10/harc-stack-forming/screenshot-2025-08-10-at-19-14-14/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png" data-orig-size="553,589" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Screenshot 2025-08-10 at 19.14.14" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png?w=282" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png?w=553" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png" alt="" class="wp-image-1742" style="aspect-ratio:0.938895177722436;width:779px;height:auto"/><figcaption class="wp-element-caption"><a href="https://github.com/librasteve/Air-Examples/blob/main/bin/12-formshort.raku">source code</a> </figcaption></figure>



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



<p class="wp-block-paragraph">Let’s zoom in on the form <code>is validated</code> trait:</p>



<pre class="wp-block-code"><code>has Str    $.first-names is validated(%va&lt;names&gt;);
has Str    $.last-name   is validated(%va&lt;name&gt;)   is required;
has Str    $.email       is validated(%va&lt;email&gt;)  is required is email;
has Str    $.city        is validated(%va&lt;text&gt;); </code></pre>



<p class="wp-block-paragraph">The <code>is validated</code> trait comes from the <a href="https://cro.raku.org/docs/reference/cro-webapp-form">Cro::WebApp::Form</a> class. </p>



<p class="wp-block-paragraph">As the docs say:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">… server-side validation at the field level can be specified by using the is validated($match-me, ‘Message’) trait, which will use the given validation error message if the input values fails to smartmatch against the condition. For example, it could be used with a regex:</p>



<p class="wp-block-paragraph"><code>has $.username is validated(/^&lt;[A..Za..z0..9]&gt;+$/, 'Only alphanumerics are allowed');</code></p>
</blockquote>



<p class="wp-block-paragraph">So that’s a <em>regex</em> and an error <em>Str</em> .</p>



<p class="wp-block-paragraph"><code>Air::Form</code> disables client side (browser) field validation since (i) the overlap with server side validation can be disorienting and (ii) the browser side validation UI is hideous.</p>



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



<p class="wp-block-paragraph">If you are familiar with regex (regular expression) syntax, feel free to skip this section.</p>



<p class="wp-block-paragraph">Here’s a breakdown…</p>



<pre class="wp-block-code"><code># This regex:
my regex alpha-num { ^&lt;[A..Za..z0..9]&gt;+$ }

# Explanation:

# ^                 # anchor: start of string
# &lt;[A..Za..z0..9]&gt;  # a character class including:
#                   #   A..Z → uppercase A through Z
#                   #   a..z → lowercase a through z
#                   #   0..9 → digits 0 through 9
# +                 # one or more of the above characters
# $                 # anchor: end of string

# So it matches a string made only of alphanumeric characters, 1+ long.

say "Hello123" ~~ /&lt;alpha-num&gt;/;   # True
say "hi_there" ~~ /&lt;alpha-num&gt;/;   # Nil (underscore not allowed)
say ""         ~~ /&lt;alpha-num&gt;/;   # Nil (empty string not allowed)</code></pre>



<p class="wp-block-paragraph">A regex is a character level language that does pattern matching against strings – either it matches the provided text, or if <em>not</em> rejects it. The <code>~~</code> operator is used to apply the regex to a string resulting in a matcher object. For more details dive into the Raku documents <a href="https://docs.raku.org/language/regexes">here</a>.</p>



<p class="wp-block-paragraph">Validating form fields ensures that the data users submit is safe, consistent, and free from malicious input. It protects applications from security risks while also enforcing rules like proper formats for emails, numbers, or passwords. Good validation improves user experience by catching errors early and keeping stored data clean and reliable.</p>



<h2 class="wp-block-heading">Batteries Included</h2>



<p class="wp-block-paragraph">The following validators are provided with Air::Form (via the Hash constant <code>%va</code> – error text removed for clarity):</p>



<pre class="wp-block-code"><code>constant %va = (
  text     =&gt; /^ &lt;[A..Za..z0..9\s.,_#-]&gt;+ $/,
  name     =&gt; /^ &lt;[A..Za..z.'-]&gt;+ $/,
  names    =&gt; /^ &lt;[A..Za..z\s.'-]&gt;+ $/,
  words    =&gt; /^ &lt;[A..Za..z\s]&gt;+ $/,
  notes    =&gt; /^ &lt;[A..Za..z0..9\s.,:;_#!?()%$£-]&gt;+ $/,
  postcode =&gt; /^ &lt;[A..Za..z0..9\s]&gt;+ $/,
  url      =&gt; /^ &lt;[a..z0..9:/.-]&gt;+ $/,
  tel      =&gt; /^ &lt;[0..9+()\s#-]&gt;+ $/,
  email    =&gt; /^ &lt;[a..zA..Z0..9._%+-]&gt;+ '@' 
                 &lt;[a..zA..Z0..9.-]&gt;+    '.' 
                 &lt;[a..zA..Z]&gt; ** 2..6       $/,
  ...
);</code></pre>



<p class="wp-block-paragraph">It is easy to add your own validators. Just go <code>%va&lt;myval&gt; = /regex/</code>, ‘text’; … and the examples here are easy to copy and extend. More sophisticated validation schemes can be expected in future with the application of raku Grammars.</p>



<h2 class="wp-block-heading">Next Time on this Channel</h2>



<p class="wp-block-paragraph">We are winding up this first series on HARC stack soon … next [&amp; hopefully last] time the topic is Defaulting. Going forward there is more to do – user credentials, blog posts, CRUD and so on.</p>



<p class="wp-block-paragraph">Thank you for watching this channel. Even better, review the <a href="https://github.com/librasteve/Air-Examples">Getting Started</a> advice and try it out for yourself.</p>



<p class="wp-block-paragraph">As usual, comments and feedback welcome. We are a friendly bunch over on the raku <a href="https://raku.org/community/">IRC chat</a> and <a href="https://discord.com/invite/VzYpdQ6">Discord</a>.</p>



<p class="wp-block-paragraph">~librasteve</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This is the 15th of the HARC Stack essays. Previous &lt;= Don’t forget – HARC Stack combines HTMX with raku Air, Red and Cro to supply a fresh approach to web development. Two weeks ago, back before HARC Stack became the darling child of https://raku.org fame, we had been Forming. Most of the features of […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakujourney.wordpress.com/?p=1780</id>
    <published>2025-09-14T15:23:24Z</published>
    <updated>2025-09-14T15:23:24Z</updated>
    <category term="Uncategorized"/>
    <category term="cro"/>
    <category term="css"/>
    <category term="hackernews"/>
    <category term="javascript"/>
    <category term="perl"/>
    <category term="php"/>
    <category term="programming"/>
    <category term="python"/>
    <category term="raku"/>
    <category term="web development"/>
  </entry>
  <entry>
    <title>From ASTs to RakuAST to ASTQuery</title>
    <link rel="alternate" href="https://dev.to/fco/from-asts-to-rakuast-to-astquery-c3f" type="text/html"/>
    <content type="html">&lt;p&gt;Precise code search and transformation for Raku&lt;/p&gt;

&lt;p&gt;Raku’s RakuAST opens up a powerful way to analyze and transform code by working directly with its Abstract Syntax Tree (AST). ASTQuery builds on that by offering a compact, expressive query language to find the nodes you care about,&lt;br&gt;
capture them, and even drive compile-time rewrites.&lt;/p&gt;

&lt;p&gt;This guide explains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What ASTs are and why they matter&lt;/li&gt;
&lt;li&gt;What RakuAST provides&lt;/li&gt;
&lt;li&gt;How to search ASTs and build macro-like passes&lt;/li&gt;
&lt;li&gt;How ASTQuery’s selector language works&lt;/li&gt;
&lt;li&gt;Practical examples: queries, captures, attribute filters, and rewrites&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  ASTs, Briefly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What: An AST is a structured, typed tree that represents your code after parsing (e.g., “call”, “operator
application”, “variable”).&lt;/li&gt;
&lt;li&gt;Why: Compilers, linters, and refactoring tools operate on ASTs because they capture code semantics, not just text.
This enables robust search and safe transformations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What Is RakuAST?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Raku’s AST: RakuAST is the new, structured representation of Raku code. It exposes node types like &lt;code&gt;RakuAST::Call&lt;/code&gt;,
&lt;code&gt;RakuAST::ApplyInfix&lt;/code&gt;, &lt;code&gt;RakuAST::Var&lt;/code&gt;, and more.&lt;/li&gt;
&lt;li&gt;Access: &lt;code&gt;my $ast = $code.AST;&lt;/code&gt; for strings, or &lt;code&gt;$*CU&lt;/code&gt; for the current compilation unit in a &lt;code&gt;CHECK&lt;/code&gt; phaser.&lt;/li&gt;
&lt;li&gt;Status: RakuAST is still experimental. Some node fields may not be &lt;code&gt;rw&lt;/code&gt; on your Rakudo; rebuild/replace enclosing
nodes when needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why Search ASTs?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Beyond grep: Find “function calls with an Int somewhere under args”, not just text matches.&lt;/li&gt;
&lt;li&gt;Safer refactors: Target particular node shapes and attributes to avoid false positives.&lt;/li&gt;
&lt;li&gt;Automated upgrades: Write codemods that transform legacy patterns into new APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Macro-Like Passes (Compiler-Time Rewrites)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use a &lt;code&gt;CHECK&lt;/code&gt; phaser with &lt;code&gt;use experimental :rakuast;&lt;/code&gt; to inspect/modify &lt;code&gt;$*CU&lt;/code&gt; before runtime.&lt;/li&gt;
&lt;li&gt;Typical flow:
1) Fetch &lt;code&gt;$*CU&lt;/code&gt;
2) Query nodes with ASTQuery
3) Mutate nodes (or rebuild if fields aren’t &lt;code&gt;rw&lt;/code&gt;)
(How mutable RakuAST needs to be is still being discussed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: Add '!!!' at the end of every &lt;code&gt;say&lt;/code&gt; call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use experimental :rakuast;
use ASTQuery;

CHECK {
    my $ast = $*CU;
    for $ast.&amp;amp;ast-query(Q|.call#say|).list {
        .args.push: RakuAST::StrLiteral.new: "!!!";
    }
}
say "some text"; # prints "some text!!!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ASTQuery, at a Glance
&lt;/h2&gt;

&lt;p&gt;• Query language: Describe node kinds, relationships (child/descendant/ancestor), and attributes succinctly.&lt;br&gt;
• Captures: Name nodes you want to retrieve with $name.&lt;br&gt;
• Functions: Reusable predicates referenced with &amp;amp;name.&lt;br&gt;
• Programmatic API: ast-query and ast-matcher.&lt;br&gt;
• CLI: Query files and print results in a readable form.&lt;/p&gt;
&lt;h2&gt;
  
  
  Quickstart
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use ASTQuery;

my $code = q:to/CODE/;
    sub f($x) { }
    f 42;
    say 1 * 3;
CODE

my $ast = $code.AST;

# Find Apply operator nodes where left=1 and right=3
my $ops = $ast.&amp;amp;ast-query('.apply-operator[left=1, right=3]');
say $ops.list;

# Find calls that have an Int somewhere under args
my $calls = $ast.&amp;amp;ast-query('&amp;amp;is-call[args=&amp;gt;&amp;gt;&amp;gt;.int]');
say $calls.list;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Selector Language
&lt;/h2&gt;

&lt;p&gt;Node description format:&lt;/p&gt;

&lt;p&gt;RakuAST::Class::Name.group#id[attr1, attr2=attrvalue]$name&amp;amp;function&lt;/p&gt;

&lt;p&gt;Components:&lt;/p&gt;

&lt;p&gt;• RakuAST::Class::Name: Optional full class name.&lt;br&gt;
• .group: Optional node group (alias to multiple classes).&lt;br&gt;
• #id: Optional id value compared against the node’s id field (per-type mapping).&lt;br&gt;
• [attributes]: Optional attribute matchers (see below).&lt;br&gt;
• $name: Optional capture name (one per node part).&lt;br&gt;
• &amp;amp;function: Optional function matcher (compose with AND when multiple).&lt;/p&gt;

&lt;p&gt;Relationship operators:&lt;/p&gt;

&lt;p&gt;• &lt;code&gt;&amp;gt;&lt;/code&gt;: Left has right as a child.&lt;br&gt;
• &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;: Left has right as a descendant, skipping only ignorable nodes.&lt;br&gt;
• &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;: Left has right as a descendant (any nodes allowed between).&lt;br&gt;
• &lt;code&gt;&amp;lt;&lt;/code&gt;: Right is the parent of left.&lt;br&gt;
• &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;: Right is an ancestor of left, skipping only ignorable nodes.&lt;br&gt;
• &lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt;: Right is an ancestor of left (any nodes allowed between).&lt;br&gt;
• Note: The space operator is no longer used.&lt;/p&gt;

&lt;p&gt;Ignorable nodes (skipped by &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;/&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;• RakuAST::Block, RakuAST::Blockoid, RakuAST::StatementList,&lt;br&gt;
RakuAST::Statement::Expression, RakuAST::ArgList&lt;/p&gt;

&lt;p&gt;Attribute relation operators (start traversal from attribute value when it is a RakuAST node):&lt;/p&gt;

&lt;p&gt;• &lt;code&gt;[attr=&amp;gt;MATCH]&lt;/code&gt;    child&lt;br&gt;
• &lt;code&gt;[attr=&amp;gt;&amp;gt;MATCH]&lt;/code&gt;   descendant via ignorable nodes&lt;br&gt;
• &lt;code&gt;[attr=&amp;gt;&amp;gt;&amp;gt;MATCH]&lt;/code&gt;  descendant (any nodes)&lt;/p&gt;

&lt;p&gt;Attribute value operators (compare against a literal, identifier, or regex literal):&lt;/p&gt;

&lt;p&gt;• &lt;code&gt;[attr~=value]&lt;/code&gt;   contains (substring) or regex match&lt;br&gt;
• &lt;code&gt;[attr^=value]&lt;/code&gt;   starts-with&lt;br&gt;
• &lt;code&gt;[attr$=value]&lt;/code&gt;   ends-with&lt;br&gt;
• &lt;code&gt;[attr*=/regex/]&lt;/code&gt; regex literal&lt;/p&gt;

&lt;p&gt;Notes:&lt;br&gt;
• When an attribute holds a RakuAST node, the matcher walks nested nodes via configured id fields to reach a comparable&lt;br&gt;
leaf (e.g., .call[name] → Name’s identifier).&lt;br&gt;
• Non-existent attributes never match.&lt;/p&gt;

&lt;p&gt;Captures:&lt;/p&gt;

&lt;p&gt;• Append $name to capture the current node part, e.g., &lt;code&gt;.call#say$call&lt;/code&gt; then access with &lt;code&gt;$match&amp;lt;call&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Functions:&lt;/p&gt;

&lt;p&gt;• Use &lt;code&gt;&amp;amp;name&lt;/code&gt; to apply reusable predicates; multiple functions compose with AND.&lt;/p&gt;
&lt;h2&gt;
  
  
  Built-in Groups and Functions
&lt;/h2&gt;

&lt;p&gt;Common groups:&lt;/p&gt;

&lt;p&gt;• &lt;code&gt;.call&lt;/code&gt; → RakuAST::Call&lt;br&gt;
• &lt;code&gt;.apply-operator&lt;/code&gt; → RakuAST::ApplyInfix|ApplyListInfix|ApplyPostfix|Ternary&lt;br&gt;
• &lt;code&gt;.operator&lt;/code&gt; → RakuAST::Infixish|Prefixish|Postfixish&lt;br&gt;
• &lt;code&gt;.conditional&lt;/code&gt; → RakuAST::Statement::IfWith|Unless|Without&lt;br&gt;
• &lt;code&gt;.variable&lt;/code&gt;, &lt;code&gt;.variable-usage&lt;/code&gt;, &lt;code&gt;.variable-declaration&lt;/code&gt;&lt;br&gt;
• &lt;code&gt;.statement&lt;/code&gt;, &lt;code&gt;.expression&lt;/code&gt;, &lt;code&gt;.int&lt;/code&gt;, &lt;code&gt;.str&lt;/code&gt;, &lt;code&gt;.ignorable&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Built-in &amp;amp;functions:&lt;/p&gt;

&lt;p&gt;• &lt;code&gt;&amp;amp;is-call&lt;/code&gt;, &lt;code&gt;&amp;amp;is-operator&lt;/code&gt;, &lt;code&gt;&amp;amp;is-apply-operator&lt;/code&gt;&lt;br&gt;
• &lt;code&gt;&amp;amp;is-assignment&lt;/code&gt;, &lt;code&gt;&amp;amp;is-conditional&lt;/code&gt;&lt;br&gt;
• &lt;code&gt;&amp;amp;has-var&lt;/code&gt;, &lt;code&gt;&amp;amp;has-call&lt;/code&gt;, &lt;code&gt;&amp;amp;has-int&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/FCO/ASTQuery/blob/main/REFERENCE.md" rel="noopener noreferrer"&gt;REFERENCE.md&lt;/a&gt; for the full, authoritative list of groups, functions, and id fields.&lt;/p&gt;
&lt;h2&gt;
  
  
  ID Fields (#id) and How Matching Works
&lt;/h2&gt;

&lt;p&gt;• Each RakuAST type maps to an “id field” used for #id comparisons (e.g., &lt;code&gt;RakuAST::Call&lt;/code&gt; uses &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;RakuAST::Infix&lt;/code&gt; uses&lt;br&gt;
&lt;code&gt;operator&lt;/code&gt;, &lt;code&gt;literals&lt;/code&gt; use &lt;code&gt;value&lt;/code&gt;).&lt;br&gt;
• When comparing attributes whose value is a RakuAST node, ASTQuery walks down by id fields until reaching a leaf value&lt;br&gt;
to compare.&lt;br&gt;
• For variable declarations, bare ids strip sigils for comparison:&lt;br&gt;
 • &lt;code&gt;.variable-declaration#x&lt;/code&gt; matches &lt;code&gt;my $x&lt;/code&gt;, even though the declaration’s name includes the sigil internally (if needed, you can always use &lt;code&gt;[name="$x"]&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;Find specific infix applications (left=1, right=3):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $code = q{
    for ^10 {
        if $_ %% 2 {
            say 1 * 3;
        }
    }
};
my $ast = $code.AST;

my $result = $ast.&amp;amp;ast-query: Q|.apply-operator[left=1, right=3]|;

# ast-query returns a ASTQuery::Match object
say $result.list;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you print the object itself, instead of getting the list of matched nodes, it will print something like this:&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%2Fddnscjn8ydryhymr1kzs.png" 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%2Fddnscjn8ydryhymr1kzs.png" alt=" " width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use ancestor operator &lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt; with captures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $result = $ast.&amp;amp;ast-query('RakuAST::Infix &amp;lt;&amp;lt;&amp;lt; .conditional$cond .int#2$int');
say $result.list;  # infix nodes
say $result.hash;  # captured 'cond' and 'int'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F0idijyfdatbwk2om7o52.png" 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%2F0idijyfdatbwk2om7o52.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Parent operator &lt;code&gt;&amp;lt;&lt;/code&gt; and capturing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $result = $ast.&amp;amp;ast-query('RakuAST::Infix &amp;lt; .apply-operator[right=2]$op');
say $result&amp;lt;op&amp;gt;;   # ApplyInfix nodes with right=2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Descendant operator &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; and capturing a variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $result = $ast.&amp;amp;ast-query('.call &amp;gt;&amp;gt;&amp;gt; RakuAST::Var$var');
say $result.list;  # call nodes
say $result.hash;  # captured 'var'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attribute relation traversal (from attribute node):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Calls that have an Int somewhere under args:
my $calls = $ast.&amp;amp;ast-query('&amp;amp;is-call[args=&amp;gt;&amp;gt;&amp;gt;.int]');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attribute value operators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Calls whose name contains "sa" (e.g., say)
my $q1 = $ast.&amp;amp;ast-query('.call[name~= "sa"]');

# Calls whose name starts with "s"
my $q2 = $ast.&amp;amp;ast-query('.call[name^= "s"]');

# Calls whose name ends with "y"
my $q3 = $ast.&amp;amp;ast-query('.call[name$= "y"]');

# Calls whose name matches /sa.*/
my $q4 = $ast.&amp;amp;ast-query('.call[name*=/sa.*/]');

Capturing and retrieving nodes:

my $m = $ast.&amp;amp;ast-query('.call#say$call');
my $call-node = $m&amp;lt;call&amp;gt;;
my @matched = $m.list;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reusable Function Matchers
&lt;/h2&gt;

&lt;p&gt;Register a function and use it via &amp;amp;name:&lt;/p&gt;

&lt;p&gt;• From a compiled matcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $m = ast-matcher('.call#f');
new-function('&amp;amp;f-call', $m);
$ast.&amp;amp;ast-query('&amp;amp;f-call');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;• From a callable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new-function('&amp;amp;single-argument-call' =&amp;gt; -&amp;gt; $n {
    $n.^name.starts-with('RakuAST::Call')
    &amp;amp;&amp;amp; $n.args.defined
    &amp;amp;&amp;amp; $n.args.args.defined
    &amp;amp;&amp;amp; $n.args.args.elems == 1
});
$ast.&amp;amp;ast-query('&amp;amp;single-argument-call');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;• From a selector string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new-function('&amp;amp;var-decl' =&amp;gt; '.variable-declaration');
$ast.&amp;amp;ast-query('&amp;amp;var-decl');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Programmatic API
&lt;/h2&gt;

&lt;p&gt;• &lt;code&gt;ast-query($ast, Str $selector) / ast-query($ast, $matcher)&lt;/code&gt;: Run a query and get an ASTQuery::Match (acts like&lt;br&gt;
Positional + Associative).&lt;br&gt;
• &lt;code&gt;ast-matcher(Str $selector)&lt;/code&gt;: Compile a selector once and reuse it.&lt;br&gt;
• &lt;code&gt;new-function($name, $callable|$matcher|$selector)&lt;/code&gt;: Register &amp;amp;name.&lt;br&gt;
• &lt;code&gt;add-ast-group($name, @classes)&lt;/code&gt; / &lt;code&gt;add-to-ast-group($name, *@classes)&lt;/code&gt;: Define/extend group aliases.&lt;br&gt;
• &lt;code&gt;set-ast-id($class, $id-method)&lt;/code&gt;: Configure which attribute is used as the id for #id and nested value matching.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLI Usage
&lt;/h2&gt;

&lt;p&gt;• Run against a directory or single file:&lt;br&gt;
 • &lt;code&gt;ast-query.raku 'SELECTOR' [path]&lt;/code&gt;&lt;br&gt;
• If path is omitted, it scans the current directory recursively.&lt;br&gt;
• Extensions scanned: raku, rakumod, rakutest, rakuconfig, p6, pl6, pm6.&lt;br&gt;
• Example:&lt;br&gt;
 • &lt;code&gt;ast-query.raku '.call#say &amp;gt;&amp;gt;&amp;gt; .int' lib/&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Selectors
&lt;/h2&gt;

&lt;p&gt;• Set ASTQUERY_DEBUG=1 to print a colored tree of matcher decisions, including deparsed node snippets and pass/fail per&lt;br&gt;
validator step. This helps understand why a node matched—or didn’t.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes and Caveats
&lt;/h2&gt;

&lt;p&gt;• RakuAST is experimental. It's still being discussed how mutable it will be.&lt;br&gt;
• Regex flags in /.../ literals aren’t supported in attribute value operators yet.&lt;br&gt;
• The old “space operator” for relationships is deprecated; use the explicit operators (&lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;ASTQuery lets you describe meaningful shapes in RakuAST—calls, operators, variables, and more—compose those&lt;br&gt;
descriptions, capture the nodes you want, and apply them to everything from precise code search to automated&lt;br&gt;
compiler-time refactorings. It’s a compact tool for robust code understanding and transformation.&lt;/p&gt;

&lt;p&gt;• Repo: &lt;a href="https://github.com/FCO/ASTQuery" rel="noopener noreferrer"&gt;https://github.com/FCO/ASTQuery&lt;/a&gt;&lt;br&gt;
• See &lt;a href="https://github.com/FCO/ASTQuery/blob/main/REFERENCE.md" rel="noopener noreferrer"&gt;REFERENCE.md&lt;/a&gt; for the complete catalog of groups, built-in functions, and id fields.&lt;/p&gt;

</content>
    <author>
      <name>Fernando Correa de Oliveira</name>
    </author>
    <id>https://dev.to/fco/from-asts-to-rakuast-to-astquery-c3f</id>
    <published>2025-09-14T00:39:59Z</published>
    <updated>2025-09-14T00:39:59Z</updated>
    <category term="ast"/>
    <category term="rakulang"/>
    <category term="astquery"/>
  </entry>
  <entry>
    <title>HARC Stack: Dogfooding</title>
    <link rel="alternate" href="https://rakujourney.wordpress.com/2025/09/08/harc-stack-dogfooding/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p class="wp-block-paragraph">This is the 14th of the HARC Stack essays. <a href="https://rakujourney.wordpress.com/2025/08/10/harc-stack-forming/">Previous</a> &lt;=</p>



<p class="wp-block-paragraph">As if you didn’t know, <a href="https://harcstack.org">HARC Stack</a> combines <a href="https://htmx.org">HTMX</a> with raku Air, Red and Cro to supply a fresh approach to web development.</p>



<p class="wp-block-paragraph">Hot news this week is that the Raku official website <a href="https://raku.org" rel="nofollow">https://raku.org</a> has been rewritten entire ly on HARC Stack… read on to learn more about how we eat our own dogfood. </p>



<h2 class="wp-block-heading">Raku.org</h2>



<p class="wp-block-paragraph">Here is the new site in all its glory…</p>



<figure class="wp-block-image size-large"><img width="1024" height="952" data-attachment-id="1763" data-permalink="https://rakujourney.wordpress.com/2025/09/08/harc-stack-dogfooding/screenshot-2025-09-08-at-17-23-48/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png" data-orig-size="1126,1047" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Screenshot 2025-09-08 at 17.23.48" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png?w=1024" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png?w=1024" alt="" class="wp-image-1763" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png?w=1024 1024w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png?w=300 300w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png?w=768 768w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-17.23.48.png 1126w" sizes="(max-width: 1024px) 100vw, 1024px"/></figure>



<p class="wp-block-paragraph">The site source code is available on Github here <a href="https://github.com/Raku/raku.org">https://github.com/Raku/raku.org</a> if you would like to look under the hood.</p>



<h2 class="wp-block-heading">Why?</h2>



<p class="wp-block-paragraph">The Raku community felt that a rewrite of the old site was needed, and were keen to use the various Raku web modules – especially <a href="http://cro.raku.org">Cro</a> – to implement a new site.</p>



<p class="wp-block-paragraph">From the HARC Stack side, the feeling was (i) a great opportunity to put the stack to the test at “medium” scale, (ii) a challenge to make a new attractive, informative and effective design and (iii) a great way to show that HARC Stack can serve a real-world website to the Raku community and to the wider world.</p>



<h2 class="wp-block-heading">What?</h2>



<p class="wp-block-paragraph">HARC Stack is bigly into <a href="https://htmx.org">HTMX</a> and (for now) <a href="https://picocss.com">Pico CSS</a>. These technologies were chosen since they represent a modern approach to website design and deployment. Take a look at their respective websites and you will detect some themes that resonate with the new raku.org site. Simple, clean and informative. Responsive and smartphone oriented.</p>



<p class="wp-block-paragraph">Choosing these building blocks was partly technical – as covered in previous episodes … HTMX to open the server side to Raku without giving up dynamic user experience and Pico CSS for the semantic HTML and clean, easily maintained source. And partly it was aesthetic, with an eye on ultimately making a web application library that would be a natural choice and lead to a great upgrade to raku.org.</p>



<h2 class="wp-block-heading">Why not?</h2>



<p class="wp-block-paragraph">Prior to this project HARC stack had only been put to work for small scale websites – up to 200 unique visitors per day. This fell into line with the notion that HTMX is a better fit for small scale rather than as a replacement to React for the next Google Maps or Facebook (this is a bit of a misnomer, since HTMX has few fundamental constraints to scaling to serve high traffic loads.</p>



<p class="wp-block-paragraph">HARC stack leans into active code execution to serve HTTP responses – as we have seen here with active content examples such as Counters, Todos and Live Search. This was a deliberate design trade off to maximise the dynamism behind HTMX. [Other choices can be made with the raku Cro module. The Cro template language composes a repository of templates at compile time during site launch and need less CPU cycles to serve static content.]</p>



<p class="wp-block-paragraph">HARC stack more closely follows the WordPress model where PHP code is run for every page request and a database dip is performed to serve the page. So it was an <em>interesting challenge</em> to stretch raku to a medium scale website such as raku.org.</p>



<h2 class="wp-block-heading">How Much?</h2>



<p class="wp-block-paragraph">So prior to the go live, it was important to check the speed of the new raku.org website under moderate load…. here are the results of a distributed test using BlazerMeter to load 20 simultaneous user sessions….</p>



<figure class="wp-block-image size-large"><img width="1024" height="899" data-attachment-id="1766" data-permalink="https://rakujourney.wordpress.com/2025/09/08/harc-stack-dogfooding/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-2/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png" data-orig-size="1358,1193" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png?w=1024" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png?w=1024" alt="" class="wp-image-1766" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png?w=1024 1024w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png?w=300 300w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png?w=768 768w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/482537782-c67fed07-e019-4dc8-8ae7-75529ceee40a-1.png 1358w" sizes="(max-width: 1024px) 100vw, 1024px"/></figure>



<p class="wp-block-paragraph">As you can see, the HARC stack response time remains rock solid at around 250-315ms … this is a green on Google Lighthouse – BlazeMeter is a bit more demanding so we get an amber. There are further speed ups we still have in the development backlog such as vendoring the JS libraries, minimising the SCSS and putting all the images locally. Now we have the profiling tools it is realistic to expect for sub 200ms response times from raku HARC stack.</p>



<h2 class="wp-block-heading">How Many?</h2>



<p class="wp-block-paragraph">Using basic busy hour calculations, this looks like:</p>



<pre class="wp-block-code"><code>Great — with 20 concurrent users at the peak and an average session duration of 35s, your busy-hour throughput is:
35s=0.009722h
Users/hour at peak = 20/0.009722 ≈ 2,057

To turn that into daily users for a single-peak, typical daily curve, use “Equivalent Busy Hours” (EBH) — the number of peak-equivalent hours your day contains. A typical single-peak consumer pattern is about 6 EBH.
Daily users ≈ Busy-hour users × EBH
Concentrated day (4 EBH): ~8,229 users/day
Typical single-peak (6 EBH): ~12,343 users/day ← likely
Broader peak (8 EBH): ~16,457 users/day
Very broad (10 EBH): ~20,571 users/day
If you don’t have your own hourly distribution yet, using ~6 EBH is a reasonable default → ≈ 12.3k users/day.</code></pre>



<p class="wp-block-paragraph">So much for the theory. Here is how day one of the new raku.org site looks…</p>



<figure class="wp-block-image size-large"><img width="1024" height="803" data-attachment-id="1770" data-permalink="https://rakujourney.wordpress.com/2025/09/08/harc-stack-dogfooding/screenshot-2025-09-08-at-18-31-21/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png" data-orig-size="1123,881" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Screenshot 2025-09-08 at 18.31.21" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png?w=1024" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png?w=1024" alt="" class="wp-image-1770" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png?w=1024 1024w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png?w=300 300w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png?w=768 768w, https://rakujourney.wordpress.com/wp-content/uploads/2025/09/screenshot-2025-09-08-at-18.31.21.png 1123w" sizes="(max-width: 1024px) 100vw, 1024px"/></figure>



<p class="wp-block-paragraph">Over 1000 visitors per day served without a hitch.</p>



<h2 class="wp-block-heading">Scaling Up</h2>



<p class="wp-block-paragraph">This is only the beginning of the scaling &amp; performance story for raku and HARC stack. We can look forward to a number of dimensions to ongoing improvements:</p>



<ul class="wp-block-list">
<li>HARC Stack works out of the box with cacheing solutions such as Cloudflare, going forward, the roadmap is for Air::Components to optionally be labelled as cache/nocache to better direct the downstream CDN and browser cache strategies</li>



<li>HARC Stack is open to plugin development to implement REDIS / MEMCACHE</li>



<li>Cro has deep support for distributed computing, to scale out web services across multiple collaborating servers.</li>



<li>Raku AST is a major new initiative to give the Raku MoarVM deeper introspection powers to feed into the JIT optimiser.</li>
</ul>



<h2 class="wp-block-heading">Next Time on this Channel</h2>



<p class="wp-block-paragraph">Thats enough to digest for now … next time we’ll take a closer look at Validating (we inserted this episode since the new raku.org site went live on Saturday!).</p>



<p class="wp-block-paragraph">Keep watching this channel if it feels good. Even better, follow the <a href="https://github.com/librasteve/Air-Examples">Getting Started</a> and try it out for yourself.</p>



<p class="wp-block-paragraph">As usual, comments and feedback welcome. We are a friendly bunch over on the raku <a href="https://raku.org/community/">IRC chat</a> and <a href="https://discord.com/invite/VzYpdQ6">Discord</a>.</p>



<p class="wp-block-paragraph">~librasteve</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This is the 14th of the HARC Stack essays. Previous &lt;= As if you didn’t know, HARC Stack combines HTMX with raku Air, Red and Cro to supply a fresh approach to web development. Hot news this week is that the Raku official website https://raku.org has been rewritten entire ly on HARC Stack… read on […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakujourney.wordpress.com/?p=1762</id>
    <published>2025-09-08T17:50:04Z</published>
    <updated>2025-09-08T17:50:04Z</updated>
    <category term="Uncategorized"/>
    <category term="cro"/>
    <category term="css"/>
    <category term="hackernews"/>
    <category term="javascript"/>
    <category term="perl"/>
    <category term="php"/>
    <category term="programming"/>
    <category term="python"/>
    <category term="raku"/>
    <category term="web development"/>
  </entry>
  <entry>
    <title>Create a minimal site with Elucid8</title>
    <link rel="alternate" href="https://dev.to/finanalyst/create-a-minimal-site-with-elucid8-1gf8" type="text/html"/>
    <content type="html">&lt;p&gt;The Elucid8 system can be used to create websites based on RakuDoc. The article is to show how to create a minimal website.&lt;/p&gt;

&lt;p&gt;Elucid8 ("elucidate") is still being developed, and more information can be found in the &lt;a href="https://github.com/elucid8-org" rel="noopener noreferrer"&gt;Github elucid8-org repositories&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The following need to be present:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A recent version of Rakudo v.2025.01 or later.&lt;/li&gt;
&lt;li&gt;Dart sass - &lt;a href="https://sass-lang.com/dart-sass/" rel="noopener noreferrer"&gt;see Sass website&lt;/a&gt; for installation instructions. (It will be used by a Elucid8 plugin, so it should be globally visible)&lt;/li&gt;
&lt;li&gt;Elucid8::Build - &lt;code&gt;zef install Elucid8::Build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Elucid8::Run-locally - &lt;code&gt;zef install Elucid8::Run-locally&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Assuming that the &lt;code&gt;zef&lt;/code&gt; installs &lt;code&gt;bin/&lt;/code&gt; files to a location in the PATH, then the utilities in the next section should run without problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up minimal site
&lt;/h2&gt;

&lt;p&gt;In an empty directory (to be concrete, lets call it &lt;code&gt;webdir&lt;/code&gt;), which will be the root for the website build, run the following&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;elucid8-setup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gather-sources&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elucid8-build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run-locally&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then point a browser at &lt;code&gt;localhost:5000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That is all for the minimum site.&lt;/p&gt;

&lt;p&gt;Now change the file &lt;code&gt;site-source/en/index.rakudoc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then run &lt;code&gt;elucid8-build; run-locally&lt;/code&gt; again to see the changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanation of steps
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1 Minimal files
&lt;/h4&gt;

&lt;p&gt;Here &lt;em&gt;elucid8-setup&lt;/em&gt; copies resources in the &lt;code&gt;Elucid8::Build&lt;/code&gt; distribution to create the minimal configuration entries in &lt;code&gt;webdir&lt;/code&gt;,&lt;br&gt;
a sample text and some minimal plugins.&lt;/p&gt;

&lt;p&gt;The directory structure under &lt;code&gt;webdir&lt;/code&gt; will be something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- config/
  - 01-base.raku
  - 02-plugins.raku
  - 03-plugin-options.raku
  - 04-repos
- misc/
- site-sources/
  - en/
    - index.rakudoc
    - examples.rakudoc

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Since Elucid8 is being built from the bottom up to be multi-lingual, it is intended that all of these directories can be named in a local variation. The file &lt;code&gt;config/01-base.raku&lt;/code&gt; contains the tokens that are used within &lt;em&gt;Elucid8::Build&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 2. Gathering sources
&lt;/h4&gt;

&lt;p&gt;It is intended that each set of language sources will be in a different repo. &lt;code&gt;gather-sources&lt;/code&gt; looks at &lt;code&gt;config/04-repos&lt;/code&gt; for files and repo information, clones repositories, runs &lt;code&gt;git blame&lt;/code&gt; against them and stores a file description in &lt;code&gt;misc/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After this step, &lt;code&gt;website&lt;/code&gt; will contain the file &lt;code&gt;misc/repo-info.rakuon&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the minimal website, the RakuDoc v2 specification is pulled from the Raku repository. This document also shows many of the features of RakuDoc.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;config/04-repos&lt;/code&gt; shows an example of how to map documents from the repository to subdirectories within &lt;code&gt;publication&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3 Build
&lt;/h4&gt;

&lt;p&gt;At this step, the build process starts. A processor engine is created that uses the plugins described in &lt;code&gt;config/02-plugins&lt;/code&gt;. These are run with options described in &lt;code&gt;config/03-plugin-options&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After this step, &lt;code&gt;misc/&lt;/code&gt; also contains &lt;code&gt;ui-dictionary.rakuon&lt;/code&gt;, which will have the English version of the UI tokens. When this dictionary is appropriately edited, other languages will be available.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Elucid8 makes a distinction between the language of the UI and the language of the contents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A new directory &lt;code&gt;publication/&lt;/code&gt; has now appeared, and this will contain the HTML version of the index file. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4
&lt;/h3&gt;

&lt;p&gt;At this step, a Cro app is run that takes the HTML in &lt;code&gt;publication&lt;/code&gt; and serves the files to &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customisation
&lt;/h2&gt;

&lt;p&gt;There are many ways to customise the site:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make sure to change &lt;code&gt;config/03-plugin-options&lt;/code&gt; and the &lt;code&gt;root-domain&lt;/code&gt; field of SiteMap, so that the SEO map points to your website.&lt;/li&gt;
&lt;li&gt;adding RakuDoc sources, remember to add links in index.rakudoc&lt;/li&gt;
&lt;li&gt;adding plugins to create new RakuDoc blocks&lt;/li&gt;
&lt;li&gt;use the ListFiles block to automatically include in &lt;code&gt;index.rakudoc&lt;/code&gt; all the other RakuDoc sources in your &lt;code&gt;local-sources/&lt;/code&gt; directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples of what can be done can be seen in &lt;a href="https://github.com/elucid8-org/sandpit" rel="noopener noreferrer"&gt;Sandpit repo, for Raku documentation&lt;/a&gt;&lt;/p&gt;

</content>
    <author>
      <name>Richard Hainsworth</name>
    </author>
    <id>https://dev.to/finanalyst/create-a-minimal-site-with-elucid8-1gf8</id>
    <published>2025-09-02T21:59:43Z</published>
    <updated>2025-09-02T21:59:43Z</updated>
    <category term="rakulang"/>
    <category term="webdev"/>
  </entry>
  <entry>
    <title>HARC Stack: Forming</title>
    <link rel="alternate" href="https://rakujourney.wordpress.com/2025/08/10/harc-stack-forming/" type="text/html"/>
    <content type="html">
&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;This is the 13th of the HARC Stack essays. &lt;a href="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/"&gt;Previous&lt;/a&gt; &amp;lt;=&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;As if you didn&amp;#8217;t know, &lt;a href="https://harcstack.org"&gt;HARC Stack&lt;/a&gt; combines &lt;a href="https://htmx.org"&gt;HTMX&lt;/a&gt; with raku Air, Red and Cro to supply a fresh approach to web development.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Well, Cro has an awesome, declarative way to set up forms in your web application. But&amp;#8230; before we get to the HOW, let&amp;#8217;s see the WHAT:&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Cro::WebApp::Form &amp;#8211; the movie&lt;/h2&gt;



&lt;figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"&gt;&lt;div class="wp-block-embed__wrapper"&gt;
&lt;div class="embed-youtube"&gt;&lt;iframe title="FormShort 720p" width="500" height="375" src="https://www.youtube.com/embed/l_nfkAfIcvo?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;



&lt;h2 class="wp-block-heading"&gt;Air::Examples &amp;#8211; the code&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here&amp;#8217;s a top level view of the code from Air::Examples. Using the &lt;a href="https://github.com/ab5tract/raku-intellij-plugin"&gt;Raku IntelliJ Plugin&lt;/a&gt; means I get syntax highlighting and can use with the built in folding editor:&lt;/p&gt;



&lt;figure class="wp-block-image size-full is-resized"&gt;&lt;img data-attachment-id="1742" data-permalink="https://rakujourney.wordpress.com/2025/08/10/harc-stack-forming/screenshot-2025-08-10-at-19-14-14/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png" data-orig-size="553,589" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-10 at 19.14.14" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png?w=282" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png?w=553" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-10-at-19.14.14.png" alt="" class="wp-image-1742" style="aspect-ratio:0.938895177722436;width:779px;height:auto" /&gt;&lt;figcaption class="wp-element-caption"&gt;&lt;a href="https://github.com/librasteve/Air-Examples/blob/main/bin/12-formshort.raku"&gt;source code&lt;/a&gt; &lt;/figcaption&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;So the form stuff &lt;em&gt;and&lt;/em&gt; the whole of the website generation and launch is here. So, once we have investigated the site stuff before (see HARC Stack posts passim), this week the focus is on the new stuff.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Code Walkthrough&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here we &lt;code&gt;use Air::Form&lt;/code&gt; for the first time. And we make a simple form &amp;#8211; in this case with just 4 inputs &amp;#8211; like this:&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;class Contact does Form {
    has Str $.first-names;
    has Str $.last-name is required;
    has Str $.email     is required is email;
    has Str $.city;

    ...
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;We declare a new class that &lt;code&gt;does Form&lt;/code&gt; &amp;#8230; &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&amp;#8230; consuming the Air::Form role brings in some new declarator traits, &lt;code&gt;is required&lt;/code&gt; and &lt;code&gt;is email&lt;/code&gt; &amp;#8230;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&amp;#8230; the sharp-eyed reader will note that I have dropped off the &lt;code&gt;is validated&lt;/code&gt; trait for now, more on that below &amp;#8230;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&amp;#8230; this is what they do:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;is required&lt;/code&gt; is used to control the &amp;lt;form&amp;gt; &amp;lt;input&amp;gt; required attribute&lt;/li&gt;



&lt;li&gt;&lt;code&gt;is email&lt;/code&gt; is used to set the &amp;lt;form&amp;gt; &amp;lt;input&amp;gt; type to err, email&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;Here&amp;#8217;s what the resulting HTML looks like:&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;&amp;lt;form name="Contact" hx-post="contact" hx-swap="outerHTML" novalidate=""&amp;gt;

&amp;lt;input type="hidden" name="__CSRF_TOKEN" id="__CSRF_TOKEN"     value="n0lxuoXN7U2M4DNudzi3ghI8DdJqcOVqFkAlinf0iw2HqgVsK1WmGQ7S1rbCLDTc"&amp;gt;

    &amp;lt;label for="first-names"&amp;gt;First names&amp;lt;/label&amp;gt;
    &amp;lt;input type="text" name="first-names" id="first-names"&amp;gt;

    &amp;lt;label for="last-name"&amp;gt;Last name&amp;lt;/label&amp;gt;
    &amp;lt;input type="text" name="last-name" id="last-name"&amp;gt;  

    &amp;lt;label for="email"&amp;gt;Email&amp;lt;/label&amp;gt;
    &amp;lt;input type="email" name="email" id="email"&amp;gt;

    &amp;lt;label for="city"&amp;gt;City&amp;lt;/label&amp;gt;
    &amp;lt;input type="text" name="city" id="city"&amp;gt; 

    &amp;lt;button type="submit"&amp;gt;
        Submit Contact
    &amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;



&lt;h3 class="wp-block-heading"&gt;Input Item Level&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Air::Form is synthesizing quite a lot of information to cut out repetitive typing for you. For each &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; item, you get:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;populated &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; tag and text&lt;/li&gt;



&lt;li&gt;populated id, name and type attributes (default type is &lt;code&gt;text&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;Form Level&lt;/h3&gt;



&lt;p class="wp-block-paragraph"&gt;Air::Form is creating the overall form tag, and building it as follows:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;name and &lt;code&gt;hx-post&lt;/code&gt; target url&lt;/li&gt;



&lt;li&gt;mark &lt;code&gt;nonvalidate&lt;/code&gt; (we will validate on the server side)&lt;/li&gt;



&lt;li&gt;adding hidden nonce input to suppress cross site scripting attacks&lt;/li&gt;



&lt;li&gt;adding and naming the submit &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class="wp-block-heading"&gt;Form Routes&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;The other part of our &lt;code&gt;class Contact&lt;/code&gt; is concerned with the actions on the form, as set out in &lt;code&gt;method form-routes()&lt;/code&gt;&amp;#8230;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;method form-routes {
    self.init;

    self.submit: -&amp;gt; Contact $form {
        if $form.is-valid {
            note "Got form data: $form.form-data()";
            self.finish: 'Contact info received!'
        }
        else {
            self.retry: $form
        }
    }
}&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;You need to write this method (or a variant of it) to control the actions on your form.&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;method form-routes {} is called by site to set up the form post route&lt;/li&gt;



&lt;li&gt;the form uses HTMX &amp;#8220;hx-post=&amp;#8221;$form-url&amp;#8221; hx-swap=\&amp;#8221;outerHTML\&amp;#8221;&lt;/li&gt;



&lt;li&gt;self.init initializes the form HTML with styles, validations and so on&lt;/li&gt;



&lt;li&gt;self.submit takes a &amp;amp;handler&lt;/li&gt;



&lt;li&gt;the handler is called by Cro, form field data is passed in the $form parameter&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;Essential Methods:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;$form.is-valid checks the form data against defined validations&lt;/li&gt;



&lt;li&gt;$form.form-data returns the form data as a Hash&lt;/li&gt;



&lt;li&gt;self.finish returns HTML to the client (for the HTMX swap)&lt;/li&gt;



&lt;li&gt;self.retry: $form returns the partially validated form data with errors&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;Contact.empty prepares an empty form for the first use in a page (use instead of Contact.new to avoid validation errors &amp;#8211; for example where an is required attribute is not yet provided).&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Comprehensive Form Controls&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here is an extract from the &lt;a href="https://librasteve.github.io/Air/docs/Air/Form.html"&gt;documents&lt;/a&gt; &amp;#8230;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Traits are used to describe the kinds of controls that will be used on a form. The full set of HTML5 control types are available. Remember to check browser support for them is sufficient if needing to cater to older browsers. They mostly follow the HTML 5 control names, however in a few cases alternative names are offered for convenience. Taking care to use&lt;em&gt; is email&lt;/em&gt;, &lt;em&gt;is url &lt;/em&gt;and&lt;em&gt; is telephone&lt;/em&gt; is especially helpful for mobile users since these dynamically control the input keyboard layout.&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;is password &amp;#8211; a password input&lt;/li&gt;



&lt;li&gt;is number &amp;#8211; a number input (set implicitly if a numeric type is used)&lt;/li&gt;



&lt;li&gt;is color &amp;#8211; a color input&lt;/li&gt;



&lt;li&gt;is date &amp;#8211; a date input&lt;/li&gt;



&lt;li&gt;is datetime-local / is datetime &amp;#8211; a datetime-local input&lt;/li&gt;



&lt;li&gt;is email &amp;#8211; an email input&lt;/li&gt;



&lt;li&gt;is month &amp;#8211; a month input&lt;/li&gt;



&lt;li&gt;is multiline &amp;#8211; a multiline text input (rendered as a text area); can have the number of rows and columns specified as named arguments, such as is multiline(:5rows, :60cols)&lt;/li&gt;
&lt;/ul&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;is tel / is telephone &amp;#8211; a tel input for a phone number&lt;/li&gt;



&lt;li&gt;is search &amp;#8211; a search input&lt;/li&gt;



&lt;li&gt;is time &amp;#8211; a time input&lt;/li&gt;



&lt;li&gt;is url &amp;#8211; a url input&lt;/li&gt;



&lt;li&gt;is week &amp;#8211; a week input&lt;/li&gt;



&lt;li&gt;will select { … } &amp;#8211; a select input, offering the options specified in the block, for example will select { 1..5 }. If the sigil of the attribute is @, then it will render a multi-select box. While self is not available in such a trait, it is passed as the topic of the block, so one can write a method get-options() { … } and then do will select { .get-options }. Note that currently there is no assistance with handling situations where the options should depend on another form field.&lt;/li&gt;



&lt;li&gt;is file &amp;#8211; a file upload input; the attribute will be populated with an instance of Cro::HTTP::Body::MultiPartFormData::Part, which has properties filename, body-blob (binary upload) ond body-text (decodes the body-blob to a Str)&lt;/li&gt;



&lt;li&gt;is hidden &amp;#8211; a hidden input&lt;/li&gt;
&lt;/ul&gt;



&lt;p class="wp-block-paragraph"&gt;There is no trait for checkboxes; use the Bool type instead.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;All of this great stuff is brought into Air::Form from Cro::HTTP::Form.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Next Time on this Channel&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Thats enough to digest for now &amp;#8230; next time we&amp;#8217;ll take a closer look at Validating.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Keep watching this channel if it feels good. Even better, follow the &lt;a href="https://github.com/librasteve/Air-Examples"&gt;Getting Started&lt;/a&gt; and try it out for yourself.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;As usual, comments and feedback welcome. We are a friendly bunch over on the raku &lt;a href="https://raku.org/community/"&gt;IRC chat&lt;/a&gt; and &lt;a href="https://discord.com/invite/VzYpdQ6"&gt;Discord&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;~librasteve&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This is the 13th of the HARC Stack essays. Previous &lt;= As if you didn’t know, HARC Stack combines HTMX with raku Air, Red and Cro to supply a fresh approach to web development. Well, Cro has an awesome, declarative way to set up forms in your web application. But… before we get to the […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakujourney.wordpress.com/?p=1740</id>
    <published>2025-08-10T21:15:01Z</published>
    <updated>2025-08-10T21:15:01Z</updated>
    <category term="Uncategorized"/>
    <category term="cro"/>
    <category term="css"/>
    <category term="hackernews"/>
    <category term="javascript"/>
    <category term="perl"/>
    <category term="php"/>
    <category term="programming"/>
    <category term="python"/>
    <category term="raku"/>
    <category term="web development"/>
  </entry>
  <entry>
    <title>HARC Stack: Searching</title>
    <link rel="alternate" href="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/" type="text/html"/>
    <content type="html">
&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;This is the 12th of the HARC Stack essays. &lt;a href="https://rakujourney.wordpress.com/2025/07/28/harc-stack-todoing/"&gt;Previous&lt;/a&gt; &amp;lt;=&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;By the way, &lt;a href="https://harcstack.org"&gt;HARC Stack&lt;/a&gt; combines &lt;a href="https://htmx.org"&gt;HTMX&lt;/a&gt; with raku Air, Red and Cro to supply a fresh approach to web development.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;My favourite HTMX example is the &lt;a href="https://htmx.org/examples/active-search/"&gt;Active Search&lt;/a&gt;. Just so cool to be able to do that with server side code &amp;#8211; pure genius.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Active Search &amp;#8211; the movie&lt;/h2&gt;



&lt;figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"&gt;&lt;div class="wp-block-embed__wrapper"&gt;
&lt;div class="embed-youtube"&gt;&lt;iframe title="ActiveSearch" width="500" height="375" src="https://www.youtube.com/embed/Lm9pNRd258U?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/figure&gt;



&lt;h2 class="wp-block-heading"&gt;Active Search &amp;#8211; the code&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Here&amp;#8217;s a top level view of the code. Using the &lt;a href="https://github.com/ab5tract/raku-intellij-plugin"&gt;Raku IntelliJ Plugin&lt;/a&gt; means I get syntax highlighting and can use with the built in folding editor:&lt;/p&gt;



&lt;figure class="wp-block-image size-full is-resized"&gt;&lt;img data-attachment-id="1715" data-permalink="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/screenshot-2025-08-03-at-14-41-51-2/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.41.51-1.png" data-orig-size="370,405" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-03 at 14.41.51" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.41.51-1.png?w=274" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.41.51-1.png?w=370" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.41.51-1.png" alt="" class="wp-image-1715" style="width:648px;height:auto" /&gt;&lt;figcaption class="wp-element-caption"&gt;&lt;a href="https://github.com/librasteve/Air-Examples/blob/main/bin/08-searchtable.raku"&gt;source code &lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;



&lt;h2 class="wp-block-heading"&gt;Code Layout&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;So, we have structured our code into some pieces:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;model Person&lt;/code&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;this is the Red ORM database model for our Person data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;&lt;code&gt;class SearchBox&lt;/code&gt;, &lt;code&gt;class Results&lt;/code&gt;,  &lt;code&gt;class Searchtable&lt;/code&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;together these classes provide the view and control aspects&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;



&lt;li&gt;&lt;code&gt;my $site = ...; $site.serve&lt;/code&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;this is where we compose everything into a website&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;code&gt;model Person&lt;/code&gt;&lt;/h2&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" width="346" height="160" data-attachment-id="1721" data-permalink="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/screenshot-2025-08-03-at-14-42-11-2/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.11-1.png" data-orig-size="346,160" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-03 at 14.42.11" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.11-1.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.11-1.png?w=346" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.11-1.png?w=346" alt="" class="wp-image-1721" style="aspect-ratio:2.16240234375;width:631px;height:auto" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.11-1.png 346w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.11-1.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.11-1.png?w=300 300w" sizes="(max-width: 346px) 100vw, 346px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Well, yeah pretty self explanatory. Check out previous editions (e.g. &lt;a href="https://rakujourney.wordpress.com/2025/07/13/harc-stack-modelling/"&gt;Modelling&lt;/a&gt;) and the Air &lt;a href="https://librasteve.github.io/Air/"&gt;docs&lt;/a&gt; for more on how the Red Object Relational Mapper (ORM) works.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;code&gt;class SearchBox&lt;/code&gt;&lt;/h2&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" width="534" height="340" data-attachment-id="1724" data-permalink="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/screenshot-2025-08-03-at-14-42-59/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.59.png" data-orig-size="534,340" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-03 at 14.42.59" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.59.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.59.png?w=534" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.59.png?w=534" alt="" class="wp-image-1724" style="aspect-ratio:1.5705422794117647;width:782px;height:auto" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.59.png 534w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.59.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.42.59.png?w=300 300w" sizes="(max-width: 534px) 100vw, 534px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;You should be able to recognise the SearchBox on the final webpage movie. It comprises the &lt;code&gt;h3&lt;/code&gt; title  and an &lt;code&gt;input&lt;/code&gt; field.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Like all three view classes, it &lt;code&gt;does Component&lt;/code&gt; to, errr, reflect the fact that it&amp;#8217;s a view component with a &lt;code&gt;method HTML {...}&lt;/code&gt; that is called when it is loaded.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Note the cool way HTMX applies a live UX indicator on the title when the search is underway.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Be awed by the HTMX combo of hx-put and hx-trigger&amp;#8230; which attrs are, of course, defined as Raku &lt;code&gt;Pair&lt;/code&gt;s.&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;:hx-put("$.url-path/search"),
:hx-trigger&amp;lt;keyup changed delay:500ms, search&amp;gt;,&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;So we are sending a put request with the search &lt;code&gt;needle&lt;/code&gt; every 500ms during an active search.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;code&gt;class Results&lt;/code&gt;&lt;/h2&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" width="444" height="154" data-attachment-id="1726" data-permalink="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/screenshot-2025-08-03-at-14-43-07/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.07.png" data-orig-size="444,154" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-03 at 14.43.07" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.07.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.07.png?w=444" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.07.png?w=444" alt="" class="wp-image-1726" style="aspect-ratio:2.883307965499746;width:644px;height:auto" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.07.png 444w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.07.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.07.png?w=300 300w" sizes="(max-width: 444px) 100vw, 444px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Another small component, this one provides the &lt;code&gt;tbody&lt;/code&gt; of the results table.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;&lt;code&gt;class SearchTable&lt;/code&gt;&lt;/h2&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" width="545" height="413" data-attachment-id="1729" data-permalink="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/screenshot-2025-08-03-at-14-43-53/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.53.png" data-orig-size="545,413" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-03 at 14.43.53" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.53.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.53.png?w=545" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.53.png?w=545" alt="" class="wp-image-1729" style="aspect-ratio:1.319662517498392;width:782px;height:auto" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.53.png 545w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.53.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.43.53.png?w=300 300w" sizes="(max-width: 545px) 100vw, 545px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;This class is the heart of our web application. It has an errr, &lt;code&gt;has-a&lt;/code&gt; relationship with an instance of SearchBox and an instance of Results.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;The main &lt;code&gt;method HTML&lt;/code&gt; here first shows the Searchbox and then an empty &lt;code&gt;table&lt;/code&gt; with &lt;code&gt;tbody&lt;/code&gt; marked as a target with &lt;code&gt;:id&amp;lt;search-results&amp;gt;&lt;/code&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;code&gt;method search&lt;/code&gt; takes the &lt;code&gt;is controller&lt;/code&gt; trait specifying PUT as the &lt;code&gt;http-method&lt;/code&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Here&amp;#8217;s what the server logs show on startup &amp;#8211; illustrating the addition of the &lt;code&gt;search-table//search&lt;/code&gt; PUT route by the Cro server&amp;#8230;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Air-Examples/bin &amp;gt; ./08-searchtable.raku
theme-color=green
bold-color=red
adding GET search-table/&amp;lt;Mu $id&amp;gt;
adding PUT search-table/&amp;lt;Mu $id&amp;gt;/search
adding GET nav/&amp;lt;Mu $id&amp;gt;
Starting server. Point browser at localhost:3000. Ctrl-C to stop server
&amp;#091;OK] 200 / - ::1
&amp;#091;OK] 200 /css/styles.css - ::1
&amp;#091;OK] 200 /img/bars.svg - ::1
&amp;#091;OK] 200 /img/favicon.ico - ::1
&amp;#091;OK] 200 /search-table/1/search - ::1&lt;/code&gt;&lt;/pre&gt;



&lt;p class="wp-block-paragraph"&gt;When this route is hit by the SearchBox, then the method performs the search (against firstName, lastName and email fields; writes the result list back to the &lt;code&gt;$!results&lt;/code&gt; instance and then returns the &lt;code&gt;$results&lt;/code&gt; instance (which automatically calls &lt;code&gt;method HTML&lt;/code&gt; on &lt;code&gt;$!results&lt;/code&gt;) and HTMX places the response into the &lt;code&gt;tbody&lt;/code&gt; target.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Yikes &amp;#8211; it&amp;#8217;s dynamic UX magic.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;my &lt;code&gt;$site = (...)&lt;/code&gt;&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Finally we make an instance, &lt;code&gt;$searchtable&lt;/code&gt;, and place it on the index page of our site like this:&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" width="413" height="208" data-attachment-id="1733" data-permalink="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/screenshot-2025-08-03-at-14-44-11/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.44.11.png" data-orig-size="413,208" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-03 at 14.44.11" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.44.11.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.44.11.png?w=413" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.44.11.png?w=413" alt="" class="wp-image-1733" style="aspect-ratio:1.9856509653669898;width:694px;height:auto" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.44.11.png 413w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.44.11.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-14.44.11.png?w=300 300w" sizes="(max-width: 413px) 100vw, 413px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;This use of Air::Functional should be familiar to all by now!&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Raku Sermon&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://rakujourney.wordpress.com/2025/07/28/harc-stack-todoing/"&gt;Last week&lt;/a&gt;, I sermonised about Complexity. raku is a large bags of tools for coding in functional, object oriented, declarative or procedural styles. In raku there is no single &amp;#8220;way&amp;#8221; in which we should write code.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;Air::Functional is a great tool for us to code web applications in functional style. Specifically this gives us a clean functional abstraction of HTML tags that can be intertwined with any raku code such as operators, here a &lt;code&gt;for&lt;/code&gt; loop which tees up the raku topic so that methods on the topic can take the simple form&lt;code&gt;.firstName&lt;/code&gt; and so on.&lt;/p&gt;



&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" width="346" height="69" data-attachment-id="1735" data-permalink="https://rakujourney.wordpress.com/2025/08/03/harc-stack-searching/screenshot-2025-08-03-at-18-33-57/" data-orig-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-18.33.57.png" data-orig-size="346,69" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="Screenshot 2025-08-03 at 18.33.57" data-image-description="" data-image-caption="" data-medium-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-18.33.57.png?w=300" data-large-file="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-18.33.57.png?w=346" src="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-18.33.57.png?w=346" alt="" class="wp-image-1735" style="aspect-ratio:5.015402038505096;width:605px;height:auto" srcset="https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-18.33.57.png 346w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-18.33.57.png?w=150 150w, https://rakujourney.wordpress.com/wp-content/uploads/2025/08/screenshot-2025-08-03-at-18.33.57.png?w=300 300w" sizes="(max-width: 346px) 100vw, 346px" /&gt;&lt;/figure&gt;



&lt;p class="wp-block-paragraph"&gt;Functional coding style can be taken much further in raku &amp;#8211; there is a hint of this in the &lt;code&gt;.assuming&lt;/code&gt; method that helps us to prime a function (sometimes called partial function application). &lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;However, in our goal of taming complexity, OO style also has much to offer. This weeks example leans on raku&amp;#8217;s very concise and powerful OO to decompose the inner components of the SearchTable and to make &lt;code&gt;has-a&lt;/code&gt; relationships. Most modern coders have OO skills in depth and this is a very natural way to efficiently arrange code to maximise clarity and maintainability.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;So raku&amp;#8217;s super-power on display here is its &lt;em&gt;multi-paradigm&lt;/em&gt; syntax that helps us to bring to bear the best tool for the job.&lt;/p&gt;



&lt;h2 class="wp-block-heading"&gt;Technicalities&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;An hawk eyed reader will have noticed a couple of Raku technicalities used to tune this:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;
&lt;li&gt;&lt;code&gt;.fc&lt;/code&gt; is fold case &amp;#8211; both the needle and the haystack are rendered case independent&lt;/li&gt;



&lt;li&gt;&lt;code&gt;tbody-attrs&lt;/code&gt; takes a Hash, so we need to pack the id attr with the &lt;code&gt;%(...)&lt;/code&gt; Hash literal&lt;/li&gt;



&lt;li&gt;&lt;code&gt;$!searchbox.url-path = $.url-path;&lt;/code&gt; is passed to the SearchBox at runtime &amp;#8211; setting as a default at the attr declaration &lt;code&gt;has SearchBox $.searchbox .= new: :$!title;&lt;/code&gt; is too early in the Component construction&lt;/li&gt;



&lt;li&gt;&lt;code&gt;.serve&lt;/code&gt; is a new method on &lt;code&gt;class Air::Base::Site&lt;/code&gt; (after &lt;code&gt;Air:ver&amp;lt;0.0.25+&amp;gt;&lt;/code&gt;) that greatly simplifies the launch of a HARC stack website on you local machine &lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class="wp-block-heading"&gt;Next Time on this Channel&lt;/h2&gt;



&lt;p class="wp-block-paragraph"&gt;Keep watching this channel if it feels good. Next time a bit of Forming. Even better, follow the &lt;a href="https://github.com/librasteve/Air-Examples"&gt;Getting Started&lt;/a&gt; and try it out for yourself.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;As usual, comments and feedback welcome. We are a friendly bunch over on the raku &lt;a href="https://raku.org/community/"&gt;IRC chat&lt;/a&gt; and &lt;a href="https://discord.com/invite/VzYpdQ6"&gt;Discord&lt;/a&gt;.&lt;/p&gt;



&lt;p class="wp-block-paragraph"&gt;~librasteve&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This is the 12th of the HARC Stack essays. Previous &lt;= By the way, HARC Stack combines HTMX with raku Air, Red and Cro to supply a fresh approach to web development. My favourite HTMX example is the Active Search. Just so cool to be able to do that with server side code – pure […]</div>
    </summary>
    <author>
      <name>librasteve</name>
    </author>
    <id>http://rakujourney.wordpress.com/?p=1710</id>
    <published>2025-08-03T17:49:39Z</published>
    <updated>2025-08-03T17:49:39Z</updated>
    <category term="Uncategorized"/>
    <category term="cro"/>
    <category term="css"/>
    <category term="hackernews"/>
    <category term="javascript"/>
    <category term="perl"/>
    <category term="php"/>
    <category term="programming"/>
    <category term="python"/>
    <category term="raku"/>
    <category term="web development"/>
  </entry>
  <entry>
    <title>🎮 ECS in Raku: A Toy Framework for Entities, Components, and Systems</title>
    <link rel="alternate" href="https://dev.to/fco/ecs-in-raku-a-toy-framework-for-entities-components-and-systems-nmm" type="text/html"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note&lt;/strong&gt;: This is a personal experiment. I’m not experienced in game development or ECS, and I’ve only recently learned about these concepts. This framework is not production-ready, and the API is still in flux. But I’d love your feedback! 🙏&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🧠 What is ECS?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ECS&lt;/strong&gt; stands for &lt;strong&gt;Entity-Component-System&lt;/strong&gt;, a popular architecture pattern in game development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entities&lt;/strong&gt; are just unique identifiers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components&lt;/strong&gt; are data — like position, velocity, health, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Systems&lt;/strong&gt; are the logic that runs on entities with certain components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of having objects with both data and behavior (like in OOP), ECS separates those concerns cleanly. It encourages &lt;strong&gt;data-driven&lt;/strong&gt; design and enables powerful querying and parallelism (though we’re far from that in this toy project).&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 What’s an Archetype?
&lt;/h2&gt;

&lt;p&gt;This ECS implementation uses the concept of &lt;strong&gt;archetypes&lt;/strong&gt;, which means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Entities are grouped by the exact combination of components (and optionally tags) they have.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means the world knows: &lt;em&gt;"All entities with &lt;code&gt;position&lt;/code&gt; and &lt;code&gt;velocity&lt;/code&gt;, but not &lt;code&gt;health&lt;/code&gt; are in this group."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
This makes querying more efficient and predictable — we only iterate over relevant entities per system.&lt;/p&gt;

&lt;p&gt;Archetypes are typically used in high-performance ECS engines (like Unity’s DOTS or Bevy in Rust), but here it also simplifies reasoning about how entities are grouped.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;Recently, I came across the idea of &lt;strong&gt;Entity Component System&lt;/strong&gt; (ECS) architectures, and it instantly clicked with my love for declarative APIs and composable logic.&lt;/p&gt;

&lt;p&gt;So I decided to implement a minimal ECS framework in &lt;a href="https://raku.org" rel="noopener noreferrer"&gt;Raku&lt;/a&gt; — not for performance or production use, but just to explore the paradigm and learn from it. And who knows? Maybe others in the Raku community will enjoy hacking on it too.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Demo 🎬
&lt;/h2&gt;

&lt;p&gt;Here’s a simple bouncing animation built with this ECS framework and &lt;a href="https://raku.land/zef:raku-community-modules/Raylib::Bindings" rel="noopener noreferrer"&gt;Raylib::Bindings&lt;/a&gt;:&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%2Fa05q50nbs2manl8n5mvj.gif" 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%2Fa05q50nbs2manl8n5mvj.gif" alt="Bouncing Camelia" width="600" height="279"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Code 🧩
&lt;/h2&gt;

&lt;p&gt;Here’s the full example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Raylib::Bindings;
use ECS;

constant $screen-width  = 1024;
constant $screen-height = 450;
my $white               = init-white;
my $background          = init-skyblue;
init-window($screen-width, $screen-height, "Bouncing Camelias");

my $string         = "./camelia.png";
my $camelia        = load-image($string);
my $camelia-height = $camelia.height;
my $camelia-width  = $camelia.width;
my $camelia-pos    = Vector2.init: $camelia-width/2e0, $camelia-height/2e0;
my $texture        = load-texture-from-image($camelia);
unload-image($camelia);

set-target-fps(60);
END {
    unload-texture($texture);
    close-window;
}

# We define a few basic vector operators to help with math:
sub term:&amp;lt;vector2-zero&amp;gt; { Vector2.init: 0e0, 0e0 }

multi infix:&amp;lt;+&amp;gt;(Vector2 $a, Vector2 $b) { Vector2.init: $a.x + $b.x, $a.y + $b.y }
multi infix:&amp;lt;-&amp;gt;(Vector2 $a, Vector2 $b) { Vector2.init: $a.x - $b.x, $a.y - $b.y }
multi infix:&amp;lt;*&amp;gt;(Vector2 $a, Numeric $i) { Vector2.init: $a.x * $i, $a.y * $i }
multi infix:&amp;lt;/&amp;gt;(Vector2 $a, Numeric $i) { Vector2.init: $a.x / $i, $a.y / $i }

# Then comes the fun part: defining the ECS world.

my $world = world {
    component position =&amp;gt; Vector2;
    component velocity =&amp;gt; Vector2;

    entity "camelia";

    # Input system: spawn a new “camelia” on mouse click
    system "click", :when{is-mouse-button-pressed MOUSE_BUTTON_LEFT}, -&amp;gt; {
        world-self.new-camelia:
            :position(get-mouse-position - $camelia-pos),
            :velocity(vector2-zero),
        ;
    }

    system-group "input", &amp;lt;click&amp;gt;;

    # Movement, gravity and bounce logic
    system "move", -&amp;gt; :$position! is rw, :$velocity! {
        using-params -&amp;gt; Num $delta {
            $position += $velocity * $delta
        }
    }

    system "bounce", -&amp;gt; :$position! where *.y &amp;gt;= $screen-height - $camelia-height.Num, :$velocity! where *.y &amp;gt; 0 {
        $velocity.y *= -.8
    }

    system "gravity", -&amp;gt; :$velocity! {
        using-params -&amp;gt; Num $delta {
            $velocity.y += 100 * $delta;
        }
    }

    system-group "physics", &amp;lt;move gravity bounce&amp;gt;;

    # Draw each camelia
    system "draw", -&amp;gt; :$position! {
        draw-texture-v $texture, $position, $white;
    }
}

    system "draw", -&amp;gt; :$position! {

# And finally the game loop:
until window-should-close {
    $world.input;
    $world.physics: get-frame-time;
    begin-drawing;
    clear-background $background;
    $world.draw;
    draw-fps 10, 10;
    end-drawing;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding the ECS Framework API
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;world&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;world&lt;/code&gt; function is the entry point to define your ECS universe. Inside it, you declare your components, entity types, systems, and system groups. It returns an object that you will use to create entities and run your systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;component&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;component&lt;/code&gt; function defines a component that entities can have. You can call it in two ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;component position =&amp;gt; Vector2;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or more concisely&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;component Color;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the second case, the name of the component will be automatically derived from the type by converting it to kebab-case (e.g., Color becomes "color"). This helps reduce repetition when the type name already describes the data well.&lt;/p&gt;

&lt;h3&gt;
  
  
  entity
&lt;/h3&gt;

&lt;p&gt;The entity function defines a named entity type. This name becomes a tag automatically added to all instances of that entity. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entity "ball";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, you can create new entities with $world.new-ball(...), and those entities will be tagged with "ball".&lt;/p&gt;

&lt;h3&gt;
  
  
  system
&lt;/h3&gt;

&lt;p&gt;The system keyword defines a system — a unit of logic that processes entities. By default, a system automatically performs a query based on its parameters: it runs once per entity that has all the required components and tags.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;system "gravity", -&amp;gt; :$velocity! { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This system runs once per frame for each entity with the velocity component.&lt;/p&gt;

&lt;p&gt;However, if you pass a :condition or :when parameter, the system behaves differently: it no longer queries entities, and runs only once per frame (or tick), executing only when the condition is true. This is ideal for global events like input, timers, or other non-entity-specific logic.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;system "click", :when { is-mouse-button-pressed MOUSE_BUTTON_LEFT }, -&amp;gt; {
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This system executes once per frame only if the left mouse button is pressed.&lt;/p&gt;

&lt;h3&gt;
  
  
  system-group
&lt;/h3&gt;

&lt;p&gt;The system-group function defines a reusable group of systems. This allows you to bundle related systems and execute them together. You can call the group like a method, optionally passing arguments that will be forwarded to any using-params blocks inside the systems.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;system-group "physics", &amp;lt;move gravity bounce&amp;gt;;
...
$world.physics: get-frame-time;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  using-params
&lt;/h3&gt;

&lt;p&gt;The using-params function allows a system to access parameters passed when the system or system group is invoked. This is useful for values like frame delta time or external input.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;system "gravity", -&amp;gt; :$velocity! {
    using-params -&amp;gt; Num $delta {
        $velocity.y += 100 * $delta;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the system needs a time delta value to apply acceleration due to gravity. It gets the value passed to the system group (e.g., physics: get-frame-time).&lt;/p&gt;

&lt;h3&gt;
  
  
  current-entity
&lt;/h3&gt;

&lt;p&gt;Inside a system or query, you can call current-entity to get the entity object currently being processed. This is useful for adding or removing tags or other manipulations.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if some-condition {
    current-entity.add-tag: "jumping";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you fine-grained control over the entity’s state and behavior beyond component data.&lt;/p&gt;

&lt;p&gt;world-self&lt;/p&gt;

&lt;p&gt;Inside a system or query, world-self gives you access to the current world instance. You can use it to create or modify entities, trigger systems, or manage state globally.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;world-self.new-ball: :position(...), :velocity(...);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows a system to spawn new entities as part of its logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Framework 🛠️
&lt;/h2&gt;

&lt;p&gt;Here are some things you should know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s written entirely in Raku.&lt;/li&gt;
&lt;li&gt;The world is declared with world { ... }.&lt;/li&gt;
&lt;li&gt;Components are just names mapped to types.&lt;/li&gt;
&lt;li&gt;Systems are defined using system with a name and a sub signature.&lt;/li&gt;
&lt;li&gt;The system’s parameters are automatically injected from matching entities.&lt;/li&gt;
&lt;li&gt;The using-params block lets you access runtime values (like delta time).&lt;/li&gt;
&lt;li&gt;Tag filtering, conditions, and entity creation are built-in.&lt;/li&gt;
&lt;li&gt;It’s not optimized in any way — it’s designed to be fun and expressive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next? 🚧
&lt;/h2&gt;

&lt;p&gt;Nothing is fixed. The API might change. This is just the beginning of a small experiment. If you’re curious about ECS, or if you have experience with game development and want to help shape a more solid design, please get in touch!&lt;/p&gt;

&lt;p&gt;You can find the project here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/FCO/ECS" rel="noopener noreferrer"&gt;https://github.com/FCO/ECS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to open issues, create examples, or criticize design decisions.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</content>
    <author>
      <name>Fernando Correa de Oliveira</name>
    </author>
    <id>https://dev.to/fco/ecs-in-raku-a-toy-framework-for-entities-components-and-systems-nmm</id>
    <published>2025-07-27T19:36:03Z</published>
    <updated>2025-07-27T19:36:03Z</updated>
    <category term="rakulang"/>
    <category term="ecs"/>
    <category term="gamedev"/>
    <category term="framework"/>
  </entry>
  <entry>
    <id>https://5ab5traction5.bearblog.dev/introducing-resource-wranger/</id>
    <title>Introducing `Resource::Wrangler`</title>
    <updated>2025-07-26T10:15:14.257858+00:00</updated>
    <author>
      <name>5ab5traction5</name>
      <email>hidden</email>
    </author>
    <content type="html">&lt;h2 id=what&gt;What&lt;/h2&gt;&lt;p&gt;I've recently released a new Raku module called &lt;code&gt;Resource::Wrangler&lt;/code&gt;. The idea is to provide a simple way to handle a pretty significant roadblock in the way Raku handles resources.&lt;/p&gt;
&lt;h2 id=why&gt;Why&lt;/h2&gt;&lt;p&gt;Raku distributions have a &lt;code&gt;%?RESOURCES&lt;/code&gt; variable that stores references to the resources that are declared in the &lt;code&gt;resources&lt;/code&gt; object defined in &lt;code&gt;META6.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, complications arise even as early as testing. This is because the tests will be compiled outside of the &lt;code&gt;CompUnit&lt;/code&gt; and it's the &lt;code&gt;CompUnit&lt;/code&gt; that circumscribes the extent &lt;code&gt;%?RESOURCES&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In other words, different &lt;code&gt;CompUnit&lt;/code&gt;, different &lt;code&gt;%?RESOURCES&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But even beyond that, something as seemingly straightforward as having a local copy of the resource to hand to a library can be quite convoluted.&lt;/p&gt;
&lt;h2 id=coderesourcewranglercode-to-the-rescue&gt;&lt;code&gt;Resource::Wrangler&lt;/code&gt; to the rescue&lt;/h2&gt;&lt;p&gt;By combining &lt;code&gt;Resource::Wrangler&lt;/code&gt; with dependency injection, it is now dead simple to bridge the gap between the distribution's &lt;code&gt;CompUnit&lt;/code&gt;, code that makes use of that distribution's &lt;code&gt;CompUnit&lt;/code&gt;, and the test files.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Resource::Wrangler&lt;/code&gt; utilizes role parameterization, a sort of hyper-flexible Raku-soaked take on implementing "generics" while adding a lot of characteristic spice to the possibility space.&lt;/p&gt;
&lt;h3 id=example-resourceful&gt;Example: Resourceful&lt;/h3&gt;&lt;p&gt;Here is an example directly from the test suite:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;class Resourceful {
    has $.resources handles &amp;lt;AT-KEY&amp;gt; = 
		Resource::Wrangler[{ %?RESOURCES }].new;
}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The most sensible default for parameterizing &lt;code&gt;Resource::Wrangler&lt;/code&gt; is &lt;code&gt;{ %?RESOURCES }&lt;/code&gt;, i.e. a block that returns the &lt;code&gt;%?RESOURCES&lt;/code&gt; of the current &lt;code&gt;CompUnit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Resource::Wrangler&lt;/code&gt; implements &lt;code&gt;AT-KEY&lt;/code&gt; to expose associative indexing to  &lt;code&gt;%?RESOURCES&lt;/code&gt;, allowing &lt;code&gt;Resourceful&lt;/code&gt; to do the same by declaring that &lt;code&gt;$.resources handles &amp;lt;AT-KEY&amp;gt;&lt;/code&gt;. This will be demonstrated in the example below.&lt;/p&gt;
&lt;p&gt;But then when we go to test, we can set our own &lt;code&gt;Str =&amp;gt; IO&lt;/code&gt; pairs for &lt;code&gt;Resource::Wrangler&lt;/code&gt; to reference:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;my %resources = test =&amp;gt; &amp;quot;/tmp/test&amp;quot;.IO;
my $resourceful = Resourceful.new: 
			resources =&amp;gt; Resource::Wrangler[-&amp;gt; { %resources }].new;
is &amp;quot;/tmp/test&amp;quot;.IO, $resourceful&amp;lt;test&amp;gt;, &amp;quot;Dependency injection works as expected&amp;quot;;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the block here needs a signature so as not to be mistaken for a single-argument "hash from a hash" initialization by Raku's grammar. Since &lt;code&gt;%?RESOURCES&lt;/code&gt; is actually an object rather than a "proper" hash, it doesn't need this special treatment.&lt;/p&gt;
&lt;h2 id=more-examples-incoming&gt;More examples incoming&lt;/h2&gt;&lt;p&gt;I wrote this library to address some obstacles in another project entirely, one which should have significant examples of relatively complex use of &lt;code&gt;Resource::Wrangler&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Until then, thanks for reading.&lt;/p&gt;
</content>
    <link href="https://5ab5traction5.bearblog.dev/introducing-resource-wranger/" rel="alternate"/>
    <published>2025-07-26T10:14:00+00:00</published>
  </entry>
  <entry>
    <title>raku-sparrow6 - swiss army knife for alpine linux</title>
    <link rel="alternate" href="https://dev.to/melezhik/raku-sparrow6-swiss-army-knife-for-alpine-linux-2ngh" type="text/html"/>
    <content type="html">&lt;p&gt;&lt;a href="https://github.com/melezhik/Sparrow6" rel="noopener noreferrer"&gt;Sparrow&lt;/a&gt; is a Rakulang based framework that allows to automate routine tasks, the beauty of it - one can use prepacked plugins available from public Sparrow repository - &lt;a href="https://sparrowhub.io" rel="noopener noreferrer"&gt;https://sparrowhub.io&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Sparrow framework
&lt;/h2&gt;

&lt;p&gt;Sparrow is installed as native Alpine package:&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="nb"&gt;sudo &lt;/span&gt;apk add &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="nt"&gt;--wait&lt;/span&gt; 120 &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--repository&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://dl-cdn.alpinelinux.org/alpine/edge/community &lt;span class="se"&gt;\&lt;/span&gt;
raku-sparrow6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up plugins repository&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SP6_REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://sparrowhub.io/repo
s6 &lt;span class="nt"&gt;--index-update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Search alpine plugins
&lt;/h2&gt;

&lt;p&gt;Sparrowhub has a lot of plugins, to limit search to Alpine related plugins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;s6 &lt;span class="nt"&gt;--search&lt;/span&gt; alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are now not too many of them for Alpine, eventually I am going to add more, put in comments what sort of plugins one would like to see&lt;/p&gt;

&lt;h2&gt;
  
  
  Run plugin
&lt;/h2&gt;

&lt;p&gt;To run plugin, use Sparrow cli, you can also pass parameters to a plugin. For example, to validate APKBUILD file one can use &lt;code&gt;apkbuild-strict&lt;/code&gt; plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;s6 &lt;span class="nt"&gt;--plg-run&lt;/span&gt; apkbuild-strict@path&lt;span class="o"&gt;=&lt;/span&gt;/path/to/apkbuild/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That way Sparrow plugins could be run from terminal or get inlined into shell scripts&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It'd be great to hear feedback from (Alpine) users, what sort of tasks could be implemented by Sparrow&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;Kudos to &lt;a href="https://pkgs.alpinelinux.org/packages?name=&amp;amp;branch=edge&amp;amp;repo=&amp;amp;arch=&amp;amp;maintainer=Celeste" rel="noopener noreferrer"&gt;Celeste&lt;/a&gt; - Alpine maintainer for raku-sparrow6 Alpine package creation &lt;/p&gt;

</content>
    <author>
      <name>Alexey Melezhik</name>
    </author>
    <id>https://dev.to/melezhik/raku-sparrow6-swiss-army-knife-for-alpine-linux-2ngh</id>
    <published>2025-07-23T14:30:07Z</published>
    <updated>2025-07-23T14:30:07Z</updated>
    <category term="sparrow"/>
    <category term="rakulang"/>
    <category term="alpine"/>
    <category term="linux"/>
  </entry>
  <entry>
    <title>🚀 Bringing Structural Protocols to Raku</title>
    <link rel="alternate" href="https://dev.to/fco/bringing-structural-protocols-to-raku-2ook" type="text/html"/>
    <content type="html">&lt;p&gt;Recently on &lt;code&gt;IRC&lt;/code&gt; someone asked how to add methods to basic types, which reminded me of an old experimental project of mine: Protocol. Its goal is to explore a structural style of interface in Raku—distinct from Raku’s nominal roles—echoing how Go’s interfaces work by method shape rather than explicit declaration.  ￼ ￼ ￼&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 Structural vs. Nominal (Go Inspiration vs. Raku Today)
&lt;/h2&gt;

&lt;p&gt;Raku roles are nominal: you explicitly compose (&lt;code&gt;does&lt;/code&gt;) a &lt;code&gt;role&lt;/code&gt; to promise a bundle of behavior; roles package partial behavior for reuse and are mixed in at compile- or run-time.  ￼ ￼ ￼&lt;br&gt;
Go interfaces are structural: any type whose method set matches the interface implicitly satisfies it—no prior annotation—providing “if it quacks…” flexibility with static checking.  ￼ ￼ ￼&lt;br&gt;
Structural typing differs from duck typing: structural typing is verified statically (at compile/analyze time), while duck typing relies on runtime method availability.  ￼ ￼ ￼&lt;/p&gt;
&lt;h2&gt;
  
  
  📘 What Protocol Originally Did
&lt;/h2&gt;

&lt;p&gt;Originally, declaring a protocol like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Protocol;

protocol Nameable {
    method name { ... }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;created a &lt;code&gt;subset&lt;/code&gt; of &lt;code&gt;Any&lt;/code&gt; that type-checks values by verifying the presence of a name method (the ... &lt;code&gt;yada&lt;/code&gt; marks a required placeholder).  ￼ ￼ ￼&lt;br&gt;
Subsets in Raku re-dispatch to their base type but enforce constraints at assignment / parameter binding; Protocol leveraged that to express a structural “has-method(s)” check without nominal composition.  ￼ ￼ ￼&lt;br&gt;
At first, providing concrete method bodies inside a protocol (i.e. anything other than &lt;code&gt;yada&lt;/code&gt;) was disallowed—protocols were strictly about requirements.  ￼ ￼ ￼&lt;/p&gt;
&lt;h2&gt;
  
  
  🔄 Why Evolve Beyond Pure Subsets?
&lt;/h2&gt;

&lt;p&gt;In practice you often want lightweight structural acceptance plus helper / default methods that build upon the required minimal surface (a pattern familiar from roles’ default methods or convenience wrappers around Go interface method sets).  ￼ ￼ ￼&lt;/p&gt;
&lt;h2&gt;
  
  
  🛠️ The New Behavior: Class Generation When Helpers Exist
&lt;/h2&gt;

&lt;p&gt;If a protocol now includes any concrete method bodies, Protocol generates a class (instead of only a subset) so those methods can be mixed in via coercion when needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Protocol;

protocol Nameable {
    method name { ... }  # required
    method description {
        [
            "Type: { $.^name }",
            "Name: { $.name }"
        ].join: "\n"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;Nameable&lt;/code&gt; now packages both a structural requirement (&lt;code&gt;name&lt;/code&gt;) and a concrete helper (&lt;code&gt;description&lt;/code&gt;) that becomes available after coercion/mix-in.  ￼ ￼ ￼&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 Pure Structural Checking Only? Use &lt;code&gt;ProtocolSubset&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Need only to assert “this value has method name” (no helper methods)? Parameterize with &lt;code&gt;ProtocolSubset&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my Nameable[ProtocolSubset] $with-name = Person.new: :name&amp;lt;Fernando&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This uses subset semantics: compile/runtime binding checks ensure the method’s existence, while the underlying object remains unchanged and un-augmented.  ￼ ￼ ￼&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ Need the Helper Methods? Use &lt;code&gt;ProtocolCoerce&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To use helpers like &lt;code&gt;.description&lt;/code&gt;, request coercion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub print-description(Nameable[ProtocolCoerce] $_) {
    say .description;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ProtocolCoerce&lt;/code&gt; mixes in the generated class so its concrete methods become callable—conceptually similar to mixing a role into an instance on demand.  ￼ ￼ ￼&lt;/p&gt;

&lt;h3&gt;
  
  
  🧪 About the Mixed Value vs. Original Object
&lt;/h3&gt;

&lt;p&gt;Raku’s mixin mechanism produces a new (reblessed) object when adding &lt;code&gt;roles&lt;/code&gt;/&lt;code&gt;mixins&lt;/code&gt;; the coerced value your function receives may differ in identity from the original variable, though it forwards behavior/state as defined by Raku’s &lt;code&gt;mixin&lt;/code&gt; &lt;code&gt;metaobject&lt;/code&gt; and caching rules.  ￼ ￼ ￼&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Design Trade-Offs (Why This Split Helps)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ergonomics: Structural checking (&lt;code&gt;ProtocolSubset&lt;/code&gt;) validates method presence without retrofitting roles into legacy or 3rd-party types.  ￼ ￼ ￼&lt;/li&gt;
&lt;li&gt;Extensibility: Helper methods embedded directly reduce boilerplate vs. writing separate wrapper roles or utility subs.  ￼ ￼ ￼&lt;/li&gt;
&lt;li&gt;Clarity &amp;amp; Safety: Explicit choice between mere validation (&lt;code&gt;ProtocolSubset&lt;/code&gt;) and augmentation (&lt;code&gt;ProtocolCoerce&lt;/code&gt;) avoids hidden behavior changes.  ￼ ￼ ￼&lt;/li&gt;
&lt;li&gt;Leverage Existing Semantics: Builds atop Raku subsets, mixins, and role composition models rather than inventing a wholly foreign mechanism.  ￼ ￼ ￼&lt;/li&gt;
&lt;li&gt;Parametric Pattern: Parameterization mirrors broader parametric / &lt;code&gt;mixin&lt;/code&gt; patterns in the ecosystem, easing conceptual load.  ￼ ￼ ￼&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🆚 Quick Comparison Snapshot
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Raku Role (Nominal)&lt;/th&gt;
&lt;th&gt;Go Interface (Structural)&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Require methods&lt;/td&gt;
&lt;td&gt;Consumer &lt;code&gt;does&lt;/code&gt; role; nominal link&lt;/td&gt;
&lt;td&gt;Any type with matching method set&lt;/td&gt;
&lt;td&gt;Subset check: structural (&lt;code&gt;ProtocolSubset&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add helper methods&lt;/td&gt;
&lt;td&gt;Role can define defaults&lt;/td&gt;
&lt;td&gt;Helpers usually on concrete type&lt;/td&gt;
&lt;td&gt;Concrete methods in protocol ⇒ coercible class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retroactively apply w/out editing source&lt;/td&gt;
&lt;td&gt;Mix role (instance/class)&lt;/td&gt;
&lt;td&gt;Implicit satisfaction&lt;/td&gt;
&lt;td&gt;Structural subset + optional coercion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avoid nominal coupling&lt;/td&gt;
&lt;td&gt;No (explicit name)&lt;/td&gt;
&lt;td&gt;Yes (implicit)&lt;/td&gt;
&lt;td&gt;Yes (shape-based check)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opt-in behavior augmentation&lt;/td&gt;
&lt;td&gt;Role mixin&lt;/td&gt;
&lt;td&gt;Not via interface itself&lt;/td&gt;
&lt;td&gt;ProtocolCoerce parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each cell reflects documented capabilities of roles, subsets, mixins, and structural interfaces.  ￼ ￼ ￼&lt;/p&gt;

&lt;h2&gt;
  
  
  💬 Structural Interfaces in Go (Deeper Dive)
&lt;/h2&gt;

&lt;p&gt;A Go value satisfies an interface automatically if it implements the interface’s method set—no implements clause—enabling decoupled design and interface-oriented APIs; this is a compile-time structural check distinct from dynamic duck typing.  ￼ ￼ ￼&lt;br&gt;
Community discussions and educational material reiterate the static structural nature (and its contrast with duck typing) emphasizing that interface satisfaction is derived from shape not explicit declarations.  ￼ ￼ ￼&lt;/p&gt;

&lt;h2&gt;
  
  
  🧪 Example Recap (Putting It Together)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Define structural requirements (and optionally helpers) in a protocol.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Nameable[ProtocolSubset]&lt;/code&gt; where you just need a guarantee the argument responds to .name.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Nameable[ProtocolCoerce]&lt;/code&gt; when you also want &lt;code&gt;.description&lt;/code&gt; (or other helper methods) to exist via a safe mixin/coercion process.
These steps leverage Raku’s subset validation and mixin metaobject to approximate Go-like structural acceptance with optional augmentation.  ￼ ￼ ￼&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🏁 Conclusion 🎉
&lt;/h2&gt;

&lt;p&gt;Protocol aims to blend Go-style structural typing’s flexibility with Raku’s powerful role, subset, and mixin machinery—cleanly separating validation (&lt;code&gt;ProtocolSubset&lt;/code&gt;) from augmentation (&lt;code&gt;ProtocolCoerce&lt;/code&gt;) so you can retrofit interfaces onto existing code while progressively layering reusable helper behavior.  ￼ ￼ ￼&lt;/p&gt;

</content>
    <author>
      <name>Fernando Correa de Oliveira</name>
    </author>
    <id>https://dev.to/fco/bringing-structural-protocols-to-raku-2ook</id>
    <published>2025-07-19T01:24:56Z</published>
    <updated>2025-07-19T01:24:56Z</updated>
  </entry>
  <entry>
    <id>https://5ab5traction5.bearblog.dev/for-love-of-the-underdog/</id>
    <title>For love of the underdog</title>
    <updated>2025-06-26T10:19:18.616205+00:00</updated>
    <author>
      <name>5ab5traction5</name>
      <email>hidden</email>
    </author>
    <content type="html">&lt;h2 id=or-how-to-end-up-being-able-to-legitimately-say-i-did-that-before-it-was-cool&gt;Or, how to end up being able to legitimately say "I did that before it was cool"&lt;/h2&gt;&lt;p&gt;Recently I've been exploring two programming languages that live well outside the &lt;em&gt;current mainstream&lt;/em&gt; but which in past eras of computing have existed much closer -- or directly inside of -- a &lt;em&gt;previous mainstream.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Despite of their decreased visibility today, these languages -- &lt;a href='https://aplwiki.com/wiki/Main_Page'&gt;APL&lt;/a&gt; and &lt;a href='https://www.eiffel.org/'&gt;Eiffel&lt;/a&gt; -- represent incredible and currently relevant achievements in language design. They also provide unique programming styles in a holistic fashion that my primary personal language &lt;a href='https://raku.org/'&gt;Raku&lt;/a&gt; does not. &lt;sup class="footnote-ref" id="fnref-1"&gt;&lt;a href="#fn-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;APL and Eiffel continue to provide significant value for their users today and thus are also of interest to me by fact that their continued existence is maintained through sheer commercial viability.&lt;/p&gt;
&lt;p&gt;Without software companies supporting various commercial implementations, both of these languages would have "died" out years ago. And yet, they did not.&lt;/p&gt;
&lt;p&gt;The experience of finding what I consider to be potentially priceless gems just hiding out in plain sight has reminded me of other moments in my life where I have followed my heart and ended up ahead of the curve.&lt;/p&gt;
&lt;p&gt;So please, if you will, let me take you on a shopping trip for eyeglasses in the summer of 1999...&lt;/p&gt;
&lt;h3 id=some-thick-rims-for-perspective&gt;Some thick rims for perspective&lt;/h3&gt;&lt;p&gt;I've always been terrible at conforming. Even during my not-so-non-conformist-after-all phase, those early teen years of Hot Topic and JNCO 32" cuff jeans, I was crap at fitting in with the other outcasts.&lt;/p&gt;
&lt;p&gt;For me, buying a pair of the thickest black frames I could find in the shop the summer before my second year of high school was the punkest move I could pull at the time. Let yourk inner freak fly regardless of what anyone thinks, that sounds like it should be punk, right?&lt;/p&gt;
&lt;p&gt;So, my reasoning went, wouldn't it be punk for me to embrace my dorky side?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/2pTZzo8.png" alt="Woman in futuristic-for-the-90s fashion sunglasses" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It may surprise some readers today, but I was not the only one who thought that these and other "frameless" styles were dope in the late 90s.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This was at the very, very earliest phase of thick (or even plastic of any kind) glasses frames coming back into fashion -- and the word 'hipster' had not yet been revived as a label because the fashion and lifestyle that would become the stereotype was only just beginning. (Crotchety old man voice: "Back in &lt;em&gt;my&lt;/em&gt; day, 'hipster' still referred to a subculture from the 50s and 60s who inspired the Beat poets.")&lt;/p&gt;
&lt;p&gt;The reason I wanted those glasses: I wanted to physically embrace my decision to go &lt;em&gt;full nerd&lt;/em&gt; my sophomore year (I failed spectacularly but that's a story for later).&lt;/p&gt;
&lt;p&gt;During a re-watch of Apollo 13 at a farmhouse in Iowa after dropping my sister off for her second year of college, I noticed how dope all the dudes in the control center looked in their solid black frames. I vowed to pick the thickest pair I could find.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://pmcvariety.files.wordpress.com/2017/02/mission-control.png?w=1000&amp;amp;h=562&amp;amp;crop=1" alt="A photo from the real mission control of Apollo 13" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here is a photo from the real command center during Apollo 13. Look at those tough ass frames!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=it-really-emis-not-coolem-to-do-the-thing-before-its-cool-to-do-the-thing&gt;It really &lt;em&gt;is not cool&lt;/em&gt; to do the thing before it's cool to do the thing&lt;/h3&gt;&lt;p&gt;For those that don't remember or weren't there, the glasses aesthetics in the 90s were almost entirely about disappearing the frames. When I showed up on my first day of school as a sophomore, I got reactions above what I was expecting -- and not in a good way.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.pinimg.com/originals/d0/42/60/d04260d44cdc803999d8b6b44e4ebb76.jpg" alt="Gillian Anderson as Dana Scully looking wearing eyeglasses with thin frames" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Special Agent Dana Scully with a "no-nonsense nerd" look that shows off the way the fashionable frame game was done in the 90s.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I never showed up to Henderson with  a face tattoo or a mohawk but I think at least in those cases there would have been some degree of fear or respect in the looks of shock and distaste I encountered.&lt;/p&gt;
&lt;p&gt;In just a few short years my choice would become the height of fashion but in those first trips through the crowded hallways between classes I can promise you that no one considered these glasses on my face to be fashionable. I remember my punkest friend at the time laughing behind his hand and pointing at me.&lt;/p&gt;
&lt;p&gt;"But I don't get it," I would later ask him, "I thought that doing something so non-conformist would be a punk move."&lt;/p&gt;
&lt;p&gt;I can't remember what he said, just his head shaking at my naivete.&lt;/p&gt;
&lt;p&gt;Then again, hadn't it been me who wanted to put a big flashy nerd signal on my face in the first place?&lt;/p&gt;
&lt;p&gt;"What did you expect would happen?", he asked, at some point during that conversation.&lt;/p&gt;
&lt;p&gt;I realized I didn't know. I had definitely chosen those glasses as a statement and so reactions from people were to be expected.&lt;/p&gt;
&lt;p&gt;I realized I wasn't so shocked or upset about the reactions from the people who hadn't respected me before that day.&lt;/p&gt;
&lt;p&gt;It was getting shit on by the so-called non-conformists (and so-called friends, at that) that had been unexpected.&lt;/p&gt;
&lt;h3 id=doing-something-just-because-it-is-cool-is-stupid&gt;Doing something just because it is cool is stupid&lt;/h3&gt;&lt;p&gt;Need proof? If you were able to stand on two legs on US soil at the time, I am betting you can still viscerally remember the year where everyone -- including you -- danced the Macarena non-stop. (No joke, there was no way to escape that year without some person or event forcing you to participate in a round of La Macarena.)&lt;/p&gt;
&lt;p&gt;&lt;img src="http://cdn.mamamia.com.au/wp/wp-content/uploads/2015/09/04124900/macarena-social.jpg" alt="A still image from the music video for 90s dance sensation La Macarena" /&gt;&lt;/p&gt;
&lt;p&gt;This post is already getting quite long so I will leave a deeper examination of this topic for another time. It may or may not involve juicy corporate failure analysis when it arrives.&lt;/p&gt;
&lt;h3 id=not-doing-something-just-because-it-is-cool-is-stupid-too&gt;Not doing something just because it is cool is stupid too&lt;/h3&gt;&lt;p&gt;Just deciding to want thick black frames in 1999 didn't guarantee that you would have access to them. I visited half a dozen glasses shops before I found that first pair of jet black retro-60s Calvin Kleins.&lt;/p&gt;
&lt;p&gt;I wasn't searching out these frames because I wanted to latch onto some upcoming or popular fashion, just like I wasn't following anyone else I knew in high school when I went searching out old classic albums in the local record shop. I'm not saying I was the only one buying records in that school of 1600+ students. But I can say for a fact that I was the only one with thick black rimmed eyeglasses in 1999. I still have the yearbook to prove it.&lt;/p&gt;
&lt;p&gt;By the time the term 'hipster' came to life, thick frames were commonplace. This should have great for me because my lenses are so extra that sticking them in thin frames amplifies their Coke bottle nature to deafening levels.&lt;/p&gt;
&lt;p&gt;But no, I had to be difficult about it.&lt;/p&gt;
&lt;p&gt;Thick rim ubiquity, however, diluted the impact of letting my eyeglasses communicating an inner nerdiness. Eventually those magical Calvin Kleins turned gray and broke but by then they were only a backup pair. The popularity of thick frames led me to go move on to different -- and less attractive on me -- thin frames.&lt;/p&gt;
&lt;p&gt;This was a stupid mistake but I promise you it was far from the only one I've made for similar reasons.&lt;/p&gt;
&lt;p&gt;It is important to mention that dismissing something as unimportant or trivial or wrong just because it is popular has a long history of negative consequences too.&lt;/p&gt;
&lt;p&gt;Just one non-spectacles example: I refused to start a blog in 2005 because I considered it to be a saturated space full of vanity projects and definitely too mainstream for me to be able to make an impact or "able to speak my real truth". &lt;em&gt;(What an idiot! - ed.)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=great-but-you-havent-actually-explained-how-to-do-the-cool-thing-before-it-becomes-cool-to-do-the-cool-thing&gt;Great, but you haven't actually explained how to do the cool thing before it becomes cool to do the cool thing&lt;/h3&gt;&lt;p&gt;Actually, I have. I just maybe haven't yet phrased it in it's most common manifestation: &lt;em&gt;be true to yourself&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I liked records and discovering lost classics (and trash rock, so much dollar bin trash rock), so I bought records. I wanted to look like a nerd from NASA circa 1969, so I looked for the right pair of frames until I found them.&lt;/p&gt;
&lt;p&gt;These are far from my only "early arrivals" in terms of fashion, book series, technologies, and the like. I land on these latent-but-soon-to-be-explosive gems for the simple reason that &lt;em&gt;I could care less about whether they are currently perceived as cool&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I've been alive long enough to know that no new solution arrives without delivering the next generation of problems. Your hot framework or language today is going to peak and ebb away as a new generation rebels against your dominance and against the inevitable gaps and flaws in your generation's solutions.&lt;/p&gt;
&lt;p&gt;It is highly unlikely that they will either be charitable in their critique or particularly informed about the historical dynamics that led to the constraints that they are now rebelling against. They will almost certainly throw the baby out with the bathwater, leaving themselves exposed to the flaws that will act as seeds of their own cyclical downfall.&lt;/p&gt;
&lt;p&gt;What is new, what is cool, these are so transient as to be irrelevant.&lt;/p&gt;
&lt;p&gt;If you get a job with a current hot tech stack and you actually enjoy that job enough to remain for five or ten years, when you decide to depart that hot stack will almost certainly be considered a hot pile of crap by a non-trivial segment of "cutting edge" programmers.&lt;/p&gt;
&lt;p&gt;Don't take it personally. It is in fact a required aspect of marketing this &lt;em&gt;new&lt;/em&gt; current hot tech stack that they paint your previously-viewed-as-revolutionary technologies as untrustworthy garbage.&lt;/p&gt;
&lt;p&gt;This is what the old sage types mean when they nod knowingly and say "the blade's edge cuts both ways."&lt;/p&gt;
&lt;h3 id=thats-that-shit-that-i-emdontem-like&gt;"That's that shit that I &lt;em&gt;don't&lt;/em&gt; like"&lt;/h3&gt;&lt;p&gt;It has taken me a long time to come to a place where I accept myself as capable of making a living on my own, pursuing only my own interests towards only my own ends.&lt;/p&gt;
&lt;p&gt;It's an important realization precisely because the sense of all-encompassing despair that I fell into on my way into a multi-year burnout, that despair came from a place of irreconcilable differences between what makes me okay with life and fulfilled as a human being and what a day in a huge corporate office looks like (hint: Hell has an open floor plan).&lt;/p&gt;
&lt;p&gt;So, do I want to "climb the ladder" and join some other enormous corporation to spend the major portion of my functionally useful life for the enrichment of a large pyramid of stakeholders that could care less about workers?&lt;/p&gt;
&lt;p&gt;Amazingly, as little as these enormous companies seem to ultimately care about their employees (at least relative to the Holier-Than-Life-Itself Bottom Line), it often seems that they care &lt;em&gt;even less&lt;/em&gt; about the products they put those workers to use towards.&lt;/p&gt;
&lt;p&gt;And I'm supposed to live my life improving software objects, from functions to modules to entire systems, that will never receive the love and attention that they deserve?&lt;/p&gt;
&lt;p&gt;A waking life of always either creating the next so-called "Minimum Viable Product" (deceivingly abbreviated as an "MVP"), or working on the un-loved guts of an MVP that was only intended as a quickly-replaced "Proof of Concept" that instead became an unchangeable bedrock of technical debt? -- this being the natural result of impatiently waiting business cases flocking to the "POC" "MVP" and essentially showing management's bluff that anything besides the most bare minimum viability of a product was going to land in production?&lt;/p&gt;
&lt;p&gt;No. Thanks for your kind offer, but no.&lt;/p&gt;
&lt;h3 id=embracing-my-self&gt;Embracing my self&lt;/h3&gt;&lt;p&gt;This moment of self-realization -- of realizing what I &lt;em&gt;don't want&lt;/em&gt; -- is usually the first stage of a sequence of events that leads me to a new cool thing before the hype cycle arrives.&lt;/p&gt;
&lt;p&gt;I don't believe in "discoveries" or "discoverers" so that's never been what I'm about. I sometimes remark on how I "did it before it was cool" but rarely in an unironic way (this essay outweighs any previous unironic expression by a long mile).&lt;/p&gt;
&lt;p&gt;Put another way, I could care less about planting my flag somewhere unless that's a place I actually give a shit about being.&lt;/p&gt;
&lt;p&gt;To that end, the programming languages that I will be blogging about are ones that I am using (&lt;a href='https://raku.org'&gt;Raku&lt;/a&gt;) and learning about (&lt;a href='https://aplwiki.com/wiki/Main_Page'&gt;APL&lt;/a&gt; and &lt;a href='https://www.eiffel.org/'&gt;Eiffel&lt;/a&gt;) with a great deal of thought and intention -- and with absolutely zero regard for what's fashionable in software development.&lt;/p&gt;
&lt;p&gt;Instead I'm focusing on the many ways that our current approaches are based on largely unconscious choices that are steeped in would-be-comic-if-not-so-tragic cargo cult practices -- choices are made today within a narrow focus and to resemble the choices we made yesterday but this time we will try to do it without the choices we didn't like.&lt;/p&gt;
&lt;p&gt;Will it actually solve the issue? Well, the fact that we already have good cause -- thanks to accumulated technical debt -- to patch the whole thing again tomorrow should tell us all we need to know on that front. (Code refactoring targeted at alleviating technical debt is a pinnacle form of crafting the structures of tomorrow to look and act exactly like the structures of yesterday, minus whatever annoyances that we can afford to fix at the moment).&lt;/p&gt;
&lt;p&gt;Moments of self-reflection don't need to be rare. Right now I'm only even interested in a continued career in programming if it involves using systems that have a track record of &lt;em&gt;not even being capable&lt;/em&gt; of encountering entire categories of problems that I've been facing with mainstream solutions. (These problems can be cultural as well as technical and I look forward to writing more about this topic soon.)&lt;/p&gt;
&lt;p&gt;Only time will tell how well I have decided... but I have lived through several reasons to embrace and trust my instincts.&lt;/p&gt;
&lt;p&gt;With any luck, this will be another wave of a lifetime.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;&lt;p&gt;First-class array programming for APL and design by contract for Eiffel. Raku, the polyglot of programming styles, has plenty of syntax and semantics that are applicable and amenable to these styles -- but that polyglot nature keeps Raku from centralizing them the way they are in APL and Eiffel. I am not saying this is a mark against Raku._&lt;a href="#fnref-1" class="footnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
    <link href="https://5ab5traction5.bearblog.dev/for-love-of-the-underdog/" rel="alternate"/>
    <published>2020-07-25T00:00:00+00:00</published>
  </entry>
  <entry>
    <title>A coordinated dance to identify the editor</title>
    <link rel="alternate" href="https://dev.to/finanalyst/a-coordinated-dance-to-identify-the-editor-2h4b" type="text/html"/>
    <content type="html">&lt;h2&gt;
  
  
  Adding login logic - rationale
&lt;/h2&gt;

&lt;p&gt;In a &lt;a href="https://dev.to/finanalyst/editing-rakudoc-croing-it-to-github-1507"&gt;previous article&lt;/a&gt;, I described how to take a web page source file, edit it, then send the edited source back to Github.&lt;/p&gt;

&lt;p&gt;In that post, the authorisation token &lt;code&gt;id-token&lt;/code&gt; was one I generated for myself as a Github user. It would also be possible to assign to the &lt;code&gt;hallowed glade&lt;/code&gt; (see previous article) an authorisation for a pseudo user or bot specifically set up to take user generated editing.&lt;/p&gt;

&lt;p&gt;However, when the edit is merged into the source, the author of the commit would be the bot, and not the author of the edit.&lt;/p&gt;

&lt;p&gt;Suppose, though, we want a 'credits' page listing authors and the number of commits they have made. We could run a command in the repo such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log --pretty="%an %n" | sort | uniq -c | sort -n -r
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and filter the results into a table. But authors who have entered our &lt;em&gt;hallowed glade&lt;/em&gt; will not be listed.&lt;/p&gt;

&lt;p&gt;Another concern is spamming. If we require a community user to have a Github identity, then Github will handle authorisation. If there is spamming by a &lt;em&gt;forest troll&lt;/em&gt;, it is in Github's best interest to hold that troll to account.&lt;/p&gt;

&lt;p&gt;This post explains (mostly to myself) the steps that are needed to insert a login layer.&lt;/p&gt;

&lt;p&gt;When I finally got the whole thing working, it was like a weird dance between three different entities. Looking at the documentation for the first time, all the steps seemed odd and unrelated, but once they were all put into motion, there is a logic to the whole thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;We already have a &lt;em&gt;hallowed glade&lt;/em&gt;, which is the &lt;code&gt;suggestion_box&lt;/code&gt; server. The server runs in a docker container, and has a Cro server to handle input from a websocket, a Cro client to interact with Github to create a new branch, store the edited file, and raise a Pull Request.&lt;/p&gt;

&lt;p&gt;Github allows the owner of a repo to register a 'Github app' and assign it permissions. So, the token granted during the authorisation process is a combination of the permissions of the &lt;em&gt;app&lt;/em&gt; and those of a user.&lt;/p&gt;

&lt;p&gt;It is always scary for a user to have to authorise someone else to do something on their behalf, so here is what Github says about the authorisation token:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A token has the same capabilities to access resources and perform actions on those resources that the owner of the token has, and is further limited by any scopes or permissions granted to the token. A token cannot grant additional access capabilities to a user. &lt;a href="https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-with-a-github-app-on-behalf-of-a-user" rel="noopener noreferrer"&gt;Github authorisation documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Coordination
&lt;/h2&gt;

&lt;p&gt;Here is diagram of the interaction between the browser, the server (in our case &lt;em&gt;suggestion_box&lt;/em&gt;) and Github from a great &lt;a href="https://medium.com/@tony.infisical/guide-to-using-oauth-2-0-to-access-github-api-818383862591" rel="noopener noreferrer"&gt;article by Tony on OAuth2&lt;/a&gt;:&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%2Fdmv1ptby80ryytxlhfg0.webp" 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%2Fdmv1ptby80ryytxlhfg0.webp" alt="Browser/Server/Github" width="720" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suppose we add in the request that if an editor wants to make edits on several documents (which means the page is refreshed), then it is inefficient for Github to generate an &lt;em&gt;id-token&lt;/em&gt; for each page.&lt;/p&gt;

&lt;p&gt;We can keep an object in local storage with the name of the editor and the time the first submission is accepted.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that Github issues its web tokens for a fixed period of time, by default 8 hours.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A pre-requisite is that the &lt;code&gt;Github app&lt;/code&gt;, which is our &lt;em&gt;suggestion-box&lt;/em&gt; is already registered with Github.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;The brief laid out above suggests the following series of steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a submission is made, the &lt;code&gt;editor&lt;/code&gt; field in the submission form must be consistent with Github rules:

&lt;ul&gt;
&lt;li&gt;Github has a user name policy of only alphanumeric characters + &lt;code&gt;-&lt;/code&gt;, with a minimum of three characters and a maximum of 39. &lt;/li&gt;
&lt;li&gt;Letters are case insensitive and other characters are replaced by &lt;code&gt;-&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The browser checks to see if the &lt;em&gt;editor&lt;/em&gt; has made a successful submission within the last 8 hours, and that 10 minutes is still left.

&lt;ul&gt;
&lt;li&gt;if there is no or insufficient time, the local storage is deleted.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If the &lt;em&gt;editor&lt;/em&gt; has not been verified, the &lt;em&gt;editor&lt;/em&gt; is sent to the Github login page, together with a &lt;code&gt;state&lt;/code&gt; string that contains information for the &lt;em&gt;suggestion_box&lt;/em&gt; to be able to issue a &lt;code&gt;successful submission&lt;/code&gt; message back to the browser.&lt;/li&gt;
&lt;li&gt;Whether or not the &lt;em&gt;editor&lt;/em&gt; has been verified, and in parallel with the Github verification, the suggestion information is sent to the &lt;em&gt;suggestion_box&lt;/em&gt; as outlined in my previous article.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Inside the &lt;em&gt;suggestion_box&lt;/em&gt; server:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;em&gt;editor&lt;/em&gt; is verified to see whether an &lt;em&gt;id-token&lt;/em&gt; with enough time (10 minutes) is available. If so, the suggestion is queued, and a successful message is sent back together with the remaining time on the token. &lt;/li&gt;
&lt;li&gt;If there is not enough time left, a failure message is sent back from the server to the browser.&lt;/li&gt;
&lt;li&gt;If there is no &lt;em&gt;id-token&lt;/em&gt; and ten minutes have passed after the suggestion was received with no message from Github, a failure message is sent back to the browser.&lt;/li&gt;
&lt;li&gt;When a message is received from Github, it is compared with waiting suggestions. If there is not a match between the &lt;em&gt;state&lt;/em&gt; field of a suggestion, the Github message is ignored. &lt;/li&gt;
&lt;li&gt;If the &lt;em&gt;state&lt;/em&gt; matches a waiting suggestion, the &lt;em&gt;suggestion-box&lt;/em&gt; server starts the process to get a &lt;em&gt;id-token&lt;/em&gt;. If successful, the suggestion is queued and a message is sent back to the browser containing the success and the expiration time.

&lt;ul&gt;
&lt;li&gt;if unsuccessful, a failure message is sent back to the browser&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this scheme,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the browser &lt;strong&gt;never&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;sees&lt;/em&gt;&lt;/strong&gt; the editor's &lt;em&gt;id-token&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;the actual name provided by the editor in the suggestion form does not have to be the Github name of the editor because the Github authorisation is independent of the &lt;em&gt;editor's&lt;/em&gt; name, but future submissions must use the same editor name to use the &lt;em&gt;id-token&lt;/em&gt;, which is time-limited in any case.&lt;/li&gt;
&lt;li&gt;an editor may edit several files in one session.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Cro setup
&lt;/h2&gt;

&lt;p&gt;In the previous post, the Cro app had a route for the &lt;em&gt;websocket&lt;/em&gt; and a Client section to handle putting suggestions into Github. &lt;/p&gt;

&lt;p&gt;We need to modify the Client section to use the &lt;em&gt;editor's&lt;/em&gt; &lt;em&gt;id-token&lt;/em&gt;, but essentially it remains the same.&lt;/p&gt;

&lt;p&gt;We also need to add a route which is used by Github to send login information to the server. In addition, there needs to be a way for the webserver route and the authorisation route to interact. &lt;/p&gt;

&lt;p&gt;These modifications imply a shared resource to match &lt;em&gt;editor-name&lt;/em&gt;, &lt;em&gt;id-token&lt;/em&gt;, &lt;em&gt;id-token&lt;/em&gt; expiration date. Since Cro assumes concurrency, the storage has to be thread-safe and ensure that only one thread at a time can access it. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Although the Cro documentation uses &lt;code&gt;OO::Monitor&lt;/code&gt; for this purpose, I prefer the simpler &lt;code&gt;Method::Protected&lt;/code&gt; module. The &lt;code&gt;is protected&lt;/code&gt; trait ensures that only one thread at a time can access the shared resource. For example,&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Method::Protected;
class Editor-Store {
    #| has key = editor, with two attributes :token and :time (a Date::Time)
    has %!storage;
    #| if False, makes sure editor key is deleted
    method is-editor-active( $editor --&amp;gt; Bool) is protected {
        return False unless %!storage{ $editor }:exists;
        return True if %!storage{ $editor }&amp;lt;expiration&amp;gt; &amp;gt; (now.DateTime + Duration.new(10 * 60));
        sink %!storage{$editor}:delete;
        return False
    }
    #| if there is no editor, an emptry string is returned
    method get-token( $editor --&amp;gt; Str) is protected {
        if self.is-editor-active( $editor ) { %!storage{$editor}&amp;lt;token&amp;gt; }
        else { '' }
    }
    #| expiration date
    method expiration( $editor ) is protected { %!storage{$editor} }
    #| returns the remaining time in seconds as an integer
    method time-remaining( $editor --&amp;gt; Int ) is protected {
        if self.is-editor-active( $editor ) { ( %!storage{ $editor }&amp;lt;expiration&amp;gt; - now.DateTime).Int }
        else { 0 }
    }
    #| adds editor
    method add-editor( Str $editor, DateTime $expiration, Str $token ) is protected {
        %!storage{$editor} = :$expiration, :$token;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Websocket route of the Cro app needed refactoring completely. Instead of getting all the information for an edit from the browser, typically, the edit suggestion comes first but the &lt;em&gt;editor&lt;/em&gt; and their &lt;em&gt;id-token&lt;/em&gt; comes later. So the Webocket needs to &lt;a href="https://docs.raku.org/language/concurrency#Promises" rel="noopener noreferrer"&gt;create a promise&lt;/a&gt; and also to put a timer on it.&lt;/p&gt;

&lt;p&gt;My first-draft solution is (the code needs to be cleaned up somewhat):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get -&amp;gt; 'suggestion_box' {
            web-socket :json, -&amp;gt; $incoming {
                supply whenever $incoming -&amp;gt; $message {
                    my $json = await $message.body;
                    # first filter out the handshake signal for opening a websocket
                    if $json&amp;lt;loaded&amp;gt; {
                        say strftime(DateTime.now, '%v %R') ~ ': connection made'
                            if $debug;
                        emit({ :connection&amp;lt;Confirmed&amp;gt; })
                    }
                    else {
                        if $debug {
                            say strftime(DateTime.now, '%v %R') ~ ': got suggestion, now at ' ~ +@suggestions;
                            for $json.kv -&amp;gt; $k, $v {
                                say "KEY $k =&amp;gt;\n$v"
                            }
                            say "edit suggestion finished\n";
                        }
                        my $response = sanitise( $json ); # sanitise returns an error message or 'ok'
                        my $editor := $json&amp;lt;editor&amp;gt;;
                        if $response ne 'OK' {
                            emit( {
                                :timestamp( DateTime.now.Str ),
                                :$response,
                                :$editor,
                            })
                        }
                        # handle the socket with an active editor
                        elsif $store.is-editor-active($editor) {
                            say strftime(DateTime.now, '%v %R') ~ ': editor is registered' if $debug;
                            # too little time left for token
                            if $store.time-remaining( $editor ) &amp;lt;= 10 * 60 {
                                say strftime(DateTime.now, '%v %R') ~ ': not enough time' if $debug;
                                emit( {
                                    :timestamp( DateTime.now.Str ),
                                    :response&amp;lt;TooLittleTimeOnToken&amp;gt;,
                                    :$editor,
                                })
                            }
                            else {
                                say strftime(DateTime.now, '%v %R') ~ ': handling with stored token' if $debug;
                                $json&amp;lt;id-token&amp;gt; = $store.get-token($editor);
                                @suggestions.push: $json;
                                emit( {
                                    :timestamp( DateTime.now.Str),
                                    :response&amp;lt;OK&amp;gt;,
                                    :$editor,
                                    :expiration( strftime($store.expiration($editor), '%v %R'))
                                } )
                            }
                        }
                        # the editor does not have a token, but may have in some period of time
                        else {
                            say strftime(DateTime.now, '%v %R') ~ ': editor without authorisation' if $debug;
                            my $timestamp;
                            my $response = 'NoAuthorisation';
                            my $expiration = '';
                            my $token = '';
                            my Promise $tapped-out .= new;
                            my $tap = $see-new-auths.tap( -&amp;gt; %a {
                                if %a&amp;lt;editor&amp;gt; eq $editor {
                                    $timestamp = DateTime.now.Str;
                                    $response = 'OK';
                                    $token = %a&amp;lt;token&amp;gt;;
                                    $expiration = %a&amp;lt;expiration&amp;gt;;
                                    $tapped-out.keep;
                                }
                            });
                            await Promise.anyof(
                                $tapped-out,
                                my $timer = Promise.in($auth-wait-time).then: {
                                    $response = 'NoAuthorisation';
                                }
                            ).then( { $tap.close } );
                            if $response eq 'OK' {
                                $json&amp;lt;id-token&amp;gt; = $token;
                                @suggestions.push: $json;
                                say strftime(DateTime.now, '%v %R') ~ ": authorising suggestion {$json.raku}, now at " ~ +@suggestions if $debug;
                            }
                            emit( %( :$timestamp, :$response, :$expiration, :$editor) )
                        }
                    }
                }
            }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;$tapped-out&lt;/code&gt; Promise is created so that it can be kept with &lt;code&gt;.keep&lt;/code&gt; inside the code that listens for an authorisation event.&lt;/p&gt;

&lt;p&gt;Then a separate Promise composed of the &lt;em&gt;$tapped-out&lt;/em&gt; Promise and a timer Promise is created so that whichever comes first triggers the next step. If the timer exits before an authorisation, then the edit suggestion is discarded, otherwise it is combined with the &lt;em&gt;id-token&lt;/em&gt; and queued.&lt;/p&gt;

&lt;p&gt;In the code section above, the webserver is a supply and when the &lt;code&gt;emit&lt;/code&gt; sub is called, the hash argument is mapped by Cro into a JSON object and returned to the browser that has connected to the Cro app. So it can be picked by the Javascript's websocket's &lt;code&gt;onmessage&lt;/code&gt; function, and the data used by the browser program.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Authorisation event
&lt;/h2&gt;

&lt;p&gt;When a &lt;em&gt;Github app&lt;/em&gt; is registered, a route is supplied for the authorisation data. Consequently, the server section of the Cro app has to be set up to service this route. I chose the route &lt;code&gt;/raku-auth&lt;/code&gt; (and in my code comes before the websocket, but since we are dealing with concurrent processes, the order of websocket and &lt;em&gt;raku-auth&lt;/em&gt; is irrelevant):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get -&amp;gt; 'raku-auth', :%params {
            CATCH {
                default {
                    content 'text/html', '&amp;lt;h1&amp;gt;Raku documentation&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Authorisation error.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Please report&amp;lt;/p&amp;gt;';
                    say 'error is: ', .message;
                    for .backtrace.reverse {
                        next if .file.starts-with('SETTING::');
                        next unless .subname;
                        say "  in block { .subname } at { .file } line { .line }";
                        last if .file.starts-with('NQP::')
                    }
                }
            }
            my %decoded = from-json( base64-decode( %params&amp;lt;state&amp;gt;).decode );
            say strftime(DateTime.now, '%v %R') ~ ': got from Github params: ', %params , ' state decoded: ', %decoded
                if $debug;
            my $editor = %decoded&amp;lt;editor&amp;gt;;
            my $resp = await Cro::HTTP::Client.post(
                "https://github.com/login/oauth/access_token",
                query =&amp;gt; %(
                    :$client_id,
                    :$client_secret,
                    :code( %params&amp;lt;code&amp;gt; ),
                ),
            );
            # Github returns an object with keys access_token, expires_in (&amp;amp; others not needed)
            my $body = await $resp.body;
            my %data = $body.decode.split('&amp;amp;').map(|*.split("=",2));
            # first store the data for future suggestions
            my $token = %data&amp;lt;access_token&amp;gt;;
            my $expiration = now.DateTime + Duration.new( %data&amp;lt;expires_in&amp;gt;);
            $store.add-editor($editor, $expiration, $token );
            # next put the data in a stream for suggestions that have already arrived
            $auth-stream.emit( %( :$editor, :$expiration, :$token ) );
            content 'text/html', '&amp;lt;h1&amp;gt;Raku documentation&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Editing has been authorised.&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;Thank you&amp;lt;/p&amp;gt;';
        }
        get -&amp;gt; 'suggestion_box' {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;CATCH&lt;/code&gt; phaser is only ever triggered if there is an error processing the route. If it is triggered, then the string after &lt;code&gt;content&lt;/code&gt; is  sent back to Github, which displays it in the tab containing the authorisation button. The HTML could be improved.&lt;/p&gt;

&lt;p&gt;At the end of the code, the &lt;code&gt;content&lt;/code&gt; sub similarly sends back an HTML string to indicated authorisation is successful.&lt;/p&gt;

&lt;p&gt;When a route has a query appended to it, the Cro route function &lt;code&gt;get&lt;/code&gt; captures the data into a named hash, which I have called &lt;code&gt;%params&lt;/code&gt;. Github recommends that a &lt;code&gt;state&lt;/code&gt; variable is sent when sending the user to Github for authorisation. I have chosen to send the name submitted by the editor with Base64 encoding. Since the editor name in the form and the user's Github id could be different, this adds some complexity to improve security.&lt;/p&gt;

&lt;p&gt;I have to say that the Cro syntax is easy to work with. When the data is transmitted as a JSON, there is the named &lt;code&gt;:body&lt;/code&gt; field, and with the data is transmitted as a query, there is the named &lt;code&gt;:query&lt;/code&gt; field. Otherwise the &lt;em&gt;get&lt;/em&gt; sub has a consistent syntax. Compare this to a cURL command.&lt;/p&gt;

&lt;p&gt;The parameters sent to the route include a &lt;code&gt;code&lt;/code&gt; field, which is then returned (again as a query) to Github. When it receives the code, it returns the &lt;code&gt;id-token&lt;/code&gt; for the editor. This two-fold handshake makes it difficult to impersonate someone else. &lt;/p&gt;

&lt;p&gt;In addition, Github returns the number of seconds the &lt;em&gt;id-token&lt;/em&gt; is valid for. So this needs to be combined into a DateTime both for the &lt;em&gt;suggestion-box&lt;/em&gt; server and the browser.&lt;/p&gt;

&lt;p&gt;Finally, the editor name, id-token and expiration date are both stored in a thread-safe Hash, and placed in an event stream into which the websocket has tapped. &lt;/p&gt;

&lt;p&gt;Raku's concurent structures make it easy to set up the event loop into which the &lt;em&gt;raku-auth&lt;/em&gt; route injects information and the &lt;em&gt;websocket&lt;/em&gt; listens for information. At the start of the code we have&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $auth-stream = Supplier.new;
my $see-new-auths = $auth-stream.Supply;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As can be seen from the code fragments, the &lt;em&gt;raku-auth&lt;/em&gt; route has the line &lt;code&gt;$auth-stream.emit( %(...) )&lt;/code&gt; and the &lt;em&gt;websocket&lt;/em&gt; code has the line &lt;code&gt;my $tap = $see-new-auths.tap( -&amp;gt; %a { ... })&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The first stanza supplies an item, in this case as hash, while the second listens for all items supplied. The second then determines which item to react to. &lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping secrets
&lt;/h2&gt;

&lt;p&gt;One of the pieces of data required by a &lt;em&gt;Github app&lt;/em&gt; is a 'secret' for the app. There are also several items to be provided to the Cro app.&lt;/p&gt;

&lt;p&gt;Since this Cro app is intended for a docker container, the configuration data is conveyed in Environment variables. So at the start of the app, several secret variables are extracted as (just an example here):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my $client_id = %*ENV&amp;lt;CLIENT_ID&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and these data can be temporarily saved in an environment file &lt;code&gt;env-file&lt;/code&gt;. Then when the docker image is invoked the data can be supplied:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo docker run -d --rm --env-file env-file my-docker-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Treading on toes
&lt;/h2&gt;

&lt;p&gt;As can be seen from the diagram above, getting authorisation is delicate dance, and it took me days to stop the browser, Github and the suggestion-box treading on each others' toes.&lt;/p&gt;

&lt;p&gt;First, the interaction between Github and the &lt;em&gt;suggestion-box&lt;/em&gt; server to exchange a &lt;code&gt;code&lt;/code&gt; for an &lt;code&gt;id-token&lt;/code&gt; are all conducted using the query format. That is a url ending &lt;code&gt;?data-item=stuff&amp;amp;item-two=nonsense&lt;/code&gt;, which is in turn Base64 encoded. All the Github API calls use JSON data with authorisation headers. &lt;/p&gt;

&lt;p&gt;In hindsight, we can recognise that the OAuth protocol is an industry standard, while the Github API protocols are not, so can be different. But it took me a while to work out what the strange data was being received by the server. I did not come across this behaviour as being explicitly documented.&lt;/p&gt;

&lt;p&gt;Second, Github requires that the &lt;em&gt;suggestion-box&lt;/em&gt; server is registered by the &lt;code&gt;owner&lt;/code&gt; of the &lt;strong&gt;repo&lt;/strong&gt; as a &lt;code&gt;Github app&lt;/code&gt; and specific permissions need to be allocated to it. There are dozens of permissions in over a dozen categories and the correct ones have to be given to the &lt;em&gt;Github app&lt;/em&gt;. I thought - mistakenly - that the permissions for &lt;em&gt;Pull requests&lt;/em&gt; was what I needed.&lt;/p&gt;

&lt;p&gt;Actually this was the last bug I had to overcome and it took a couple of days to figure out that the error was not in the server code, but that I had not allocated enough permissions.&lt;/p&gt;

&lt;p&gt;To summarise, the &lt;em&gt;suggestion-box&lt;/em&gt; server uses four separate Github API calls and the permissions are different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;api.github.com/repos/{$repo-name}/git/ref/heads/main&lt;/code&gt; to get the commit sha for the &lt;em&gt;repo-name&lt;/em&gt; - this is public data and the permission is mandatory for an App, so it does not need to be specifically added&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api.github.com/repos/{$repo-name}/git/refs&lt;/code&gt; (with data) to create a reference - this requires the &lt;code&gt;Contents&lt;/code&gt; permission with read/write&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api.github.com/repos/{$repo-name}/contents/{$file-path}&lt;/code&gt; to supply the edited - this requires the &lt;code&gt;Contents&lt;/code&gt; permission&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api.github.com/repos/{$repo-name}/pulls&lt;/code&gt; to create a pull request of the new branch - this requires the &lt;code&gt;Pull Request&lt;/code&gt; permission&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Some 'simple' requests have complex solutions. Although Cro and Raku's concurrent structures take a while to understand, they are easy to apply.&lt;/p&gt;

</content>
    <author>
      <name>Richard Hainsworth</name>
    </author>
    <id>https://dev.to/finanalyst/a-coordinated-dance-to-identify-the-editor-2h4b</id>
    <published>2025-04-25T14:47:44Z</published>
    <updated>2025-04-25T14:47:44Z</updated>
    <category term="raku"/>
    <category term="github"/>
    <category term="rakulang"/>
    <category term="cro"/>
  </entry>
  <entry>
    <title>Editing RakuDoc, CRO'ing it to Github</title>
    <link rel="alternate" href="https://dev.to/finanalyst/editing-rakudoc-croing-it-to-github-1507" type="text/html"/>
    <content type="html">&lt;h2&gt;
  
  
  All I want is to correct a one-letter typo
&lt;/h2&gt;

&lt;p&gt;The ask, expressed by our website users, is simple enough, edit a source from a GitHub repo in a browser, then save the edited version back.&lt;/p&gt;

&lt;p&gt;How difficult is that? It's easy to point the browser at the file in the repo, and GitHub has an editor ...&lt;/p&gt;

&lt;p&gt;The problem comes from authorisation, and bad actors wanting to add stupid stuff to files - like: I'm the brilliantish shop for high-ent wazzoo's. Come take a look at &lt;code&gt;http://rip-me-off.darkweb.cosmo&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Github's editor is easy to use - if you have commit permissions on the repo, otherwise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you need to clone the repo,&lt;/li&gt;
&lt;li&gt;correct the one letter typo in a single file,&lt;/li&gt;
&lt;li&gt;raise a PR. 
Which is fine if you know what a 'clone' is, or a 'repo' is, or a 'PR'. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;u&gt;But its only one letter!??&lt;/u&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Also, our website text source is written in RakuDoc (not MarkDown, but that's another story) and so it would be nice to be able to see what the change looks like. As always a seemingly trivial mistake, such as deleting a &lt;code&gt;&amp;lt;&lt;/code&gt; in the wrong place, can have severe effects.&lt;/p&gt;

&lt;p&gt;So, it would be nice to see an HTML rendering of the edited text before submitting it back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first steps into the forest
&lt;/h2&gt;

&lt;p&gt;It seems doable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the content of the file from Github - there is a simple URL and the Javascript &lt;code&gt;fetch&lt;/code&gt; function. &lt;/li&gt;
&lt;li&gt;Put the content into an online editor - there are a few editor libraries, which give you all sorts of control; I chose one.&lt;/li&gt;
&lt;li&gt;Get the content back from the editor at some point, send it to a renderer - I put my &lt;code&gt;Rakuast::RakuDoc::Render&lt;/code&gt; into a docker container, wrote a very simple &lt;code&gt;Cro&lt;/code&gt; app that has all the logic for a websocket. The app expects RakuDoc source, and sends back the rendered HTML, which is then added into a &lt;code&gt;div&lt;/code&gt; next to the online editor. &lt;/li&gt;
&lt;li&gt;Send the edited version of the file back to Github - oh. I'm lost in the forest.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll not explain tasks 1-3 above and focus on task 4.&lt;/p&gt;

&lt;h2&gt;
  
  
  The path through the forest
&lt;/h2&gt;

&lt;p&gt;While getting the content is easy, returning it is hard. The API documentation is written for developers who understand Github and HTTP requests. &lt;/p&gt;

&lt;p&gt;I spent two days wandering though the API documentation, searching for tutorials, (and Github's own discussion forum seems to be flooded with trolls, so is not a good place to look).&lt;/p&gt;

&lt;p&gt;I even resorted - gasp - to ChatGPT. Whilst the code it suggested was not remotely what I wanted, the 'solutions' demonstrated a remarkably simple truth. Perhaps I should have realised it on my own, but in all my documentation searches I had not read a hint about it.&lt;/p&gt;

&lt;p&gt;The simple truth: getting a patch of a file to the repo maintainers could &lt;em&gt;only&lt;/em&gt; be done in a &lt;strong&gt;sequence&lt;/strong&gt; of steps, not the single step that I was looking for.&lt;/p&gt;

&lt;p&gt;It is obvious that Github wants to ensure that only authorised users can change the state of a repo. Authorisation is accomplished by accompanying any request for a change with a &lt;strong&gt;&lt;em&gt;token&lt;/em&gt;&lt;/strong&gt; that has a limited duration, is unique to a recognised user on Github, and has permissions for the repo. &lt;/p&gt;

&lt;p&gt;While it is possible to get and use such a token for an arbitrary user, by sending them to Github to log in, the process is an added layer of complexity. For simplicity, we shall consider that a token has been generated and call it &lt;code&gt;id-token&lt;/code&gt;. (For development, I used one generated for myself)&lt;/p&gt;

&lt;h2&gt;
  
  
  The steps on the map
&lt;/h2&gt;

&lt;p&gt;In generalised terms, here are the steps to sending a suggestion for editing a file to the Github repo. (I'll explain some of the jargon with each step).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Obtain the contents of the &lt;code&gt;file&lt;/code&gt; and its &lt;code&gt;sha&lt;/code&gt; from &lt;code&gt;repo&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Github stores all the information developers use in &lt;em&gt;files&lt;/em&gt;. Each is tagged with a &lt;em&gt;sha&lt;/em&gt;, and is located in a &lt;em&gt;repository&lt;/em&gt; or &lt;em&gt;repo&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Actually Github has a two layer structure of &lt;em&gt;owner&lt;/em&gt;/&lt;em&gt;repo-name&lt;/em&gt;, so in this article, when I say &lt;em&gt;repo&lt;/em&gt;, I mean the combination of &lt;em&gt;owner&lt;/em&gt;/&lt;em&gt;repo-name&lt;/em&gt;. For example, the site I am working on uses the source from the &lt;code&gt;Raku/doc&lt;/code&gt; Github storage, where &lt;code&gt;Raku&lt;/code&gt; is the organisation that owns the storage, and &lt;code&gt;doc&lt;/code&gt; is the repo in which Raku holds its documentation suite.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sha&lt;/code&gt; is the encrypted sum of the entire file, and is presented as a 40 digit hexadecimal string. The maths of &lt;em&gt;shas&lt;/em&gt; is quite interesting but not relevant here. Suffice it to say that if a file is changed at all, the &lt;em&gt;shas&lt;/em&gt; of the two files (before the edit and after it) will be different (for the pedantic, I'll add 'with high probability').&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;In fact&lt;/em&gt;, this step can all be done in the browser because there is no change in state of the Github storage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Obtain the latest &lt;code&gt;sha&lt;/code&gt; or &lt;code&gt;commit&lt;/code&gt; for the &lt;code&gt;repo&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just as the contents of one file at one point in time can be identified by a &lt;em&gt;sha&lt;/em&gt; of the file, so too can the contents of the whole &lt;em&gt;repo&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new &lt;code&gt;branch&lt;/code&gt; or reference point in the &lt;em&gt;repo&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In order to retain both the existing content of a &lt;em&gt;repo&lt;/em&gt; and the suggested new content, the new content is held in a new part of the &lt;em&gt;repo&lt;/em&gt;, and this new 'section' is called a &lt;strong&gt;branch&lt;/strong&gt;. It can also be thought of as a reference point in the history of the &lt;em&gt;repo&lt;/em&gt;. At some point the maintainer of the &lt;em&gt;repo&lt;/em&gt; can accept the new content (merging it into the main part of the &lt;em&gt;repo&lt;/em&gt;), or reject it.&lt;/li&gt;
&lt;li&gt;Creating a &lt;em&gt;branch&lt;/em&gt; changes the state of the &lt;em&gt;repo&lt;/em&gt;, so Github only allows a recognised agent to do this. So, this step has to be accompanied by an &lt;em&gt;id-token&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The information needed by Github for this step is

&lt;ol&gt;
&lt;li&gt;The name of the &lt;em&gt;repo&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;sha&lt;/em&gt; of the &lt;em&gt;repo&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;em&gt;id-token&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A name for the &lt;em&gt;branch&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A description of the &lt;em&gt;branch&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Move a copy in &lt;code&gt;BASE64&lt;/code&gt; format of the edited file to the new branch&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;BASE64&lt;/em&gt; is a way of coding a file so that it can be transmitted safely across the internet.&lt;/li&gt;
&lt;li&gt;This step needs

&lt;ol&gt;
&lt;li&gt;The name of the repo&lt;/li&gt;
&lt;li&gt;The name of the branch&lt;/li&gt;
&lt;li&gt;The path of the file inside the branch&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;sha&lt;/em&gt; of the &lt;strong&gt;original&lt;/strong&gt; file&lt;/li&gt;
&lt;li&gt;The new contents of the &lt;em&gt;file&lt;/em&gt; in &lt;em&gt;BASE64&lt;/em&gt; format&lt;/li&gt;
&lt;li&gt;An &lt;em&gt;id-token&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Raise a &lt;code&gt;PR&lt;/code&gt; for the &lt;em&gt;branch&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;PR&lt;/code&gt; is a &lt;strong&gt;&lt;em&gt;pull request&lt;/em&gt;&lt;/strong&gt;, and it is a suggestion to the &lt;em&gt;repo&lt;/em&gt; maintainer to merge the suggested changes of the file into the main content of the &lt;em&gt;repo&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This&lt;/strong&gt; is the end result we want.&lt;/li&gt;
&lt;li&gt;A branch may contain changes to many files (not just one), and so a &lt;em&gt;PR&lt;/em&gt; is for the whole branch (for the pedantic: 'typically').&lt;/li&gt;
&lt;li&gt;This step needs

&lt;ol&gt;
&lt;li&gt;An &lt;em&gt;id-token&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;repo&lt;/em&gt; name&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;branch&lt;/em&gt; name&lt;/li&gt;
&lt;li&gt;A title for the &lt;em&gt;PR&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A description of the &lt;em&gt;PR&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Even though only one letter in one file may need to be changed, the API is set up (reasonably) for many changes to many files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beware ... the trolls and bogey men
&lt;/h2&gt;

&lt;p&gt;Can we do this in the browser? Uh, well ... yes, but &lt;strong&gt;No&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The problem is that everything in a browser can be examined by the world. So if you put an &lt;em&gt;id-token&lt;/em&gt; in a browser, it can be extracted from the browser, and then a bad actor can use the token to do silly stuff.&lt;/p&gt;

&lt;p&gt;So, each of the steps above which require an &lt;em&gt;id-token&lt;/em&gt; have to be executed from a place that can be defended, such as inside a container where the &lt;em&gt;id-token&lt;/em&gt; can be hidden and renewed on a regular basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a hallowed glade in the forest
&lt;/h2&gt;

&lt;p&gt;The solution is to create a safe location - hallowed glade - in which the &lt;em&gt;id-token&lt;/em&gt; can be stored, and from which the calls to Github can safely be executed.&lt;/p&gt;

&lt;p&gt;So let us create a container with a Cro application. The container will have a websocket to accept the edited file from the browser, and then separately interact with Github.&lt;/p&gt;

&lt;p&gt;The Cro documentation was written by a genius for developers with experience, unlike me. They are daunting and confusing - it took days of work to figure things out. However, Cro does make it easy to set up the steps listed above.&lt;/p&gt;

&lt;p&gt;The first thing to realise is that &lt;code&gt;Cro::HTTP::Client&lt;/code&gt; and &lt;code&gt;Cro::HTTP::Server&lt;/code&gt; / &lt;code&gt;Cro::HTTP::Router&lt;/code&gt; are - at least externally - independent of each other, but we will need both. &lt;/p&gt;

&lt;p&gt;We will need the &lt;strong&gt;&lt;em&gt;Server&lt;/em&gt;&lt;/strong&gt; to listen for the data coming down the websocket, and then &lt;strong&gt;&lt;em&gt;Client&lt;/em&gt;&lt;/strong&gt; to move the edited file to the Github repo. &lt;/p&gt;

&lt;p&gt;Since step 1 above is done in-browser, it needs to be implemented in Javascript. I will not deal with that here, except to say, that when the content is fetched from Github, the &lt;em&gt;sha&lt;/em&gt; of the file is saved. The in-browser code finally sends along a websocket a JSON object with the following fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repo    - the owner/repo-name combination&lt;/li&gt;
&lt;li&gt;path    - the path of the file inside the repo &lt;/li&gt;
&lt;li&gt;sha     - the sha of the file&lt;/li&gt;
&lt;li&gt;content - the &lt;em&gt;edited&lt;/em&gt; content in BASE64 form&lt;/li&gt;
&lt;li&gt;editor  - the person editing the file&lt;/li&gt;
&lt;li&gt;comment - why the edits are made&lt;/li&gt;
&lt;li&gt;patch   - a Patch between the original and edited files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last three are not strictly needed, but can be used for some sanity testing.&lt;/p&gt;

&lt;p&gt;Lets assume the web socket has a route &lt;code&gt;suggestion_box&lt;/code&gt;, then the following is the code for a Cro application to get the data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Cro::HTTP::Log::File;
use Cro::HTTP::Server;
use Cro::HTTP::Router;
use Cro::HTTP::Client;
use Cro::HTTP::Router::WebSocket;
use DateTime::strftime; # a helper to provide nice time formats

my $patch-limit = 5 * 2 ** 10; # 5k limit of chars
my $comment-limit = 1 * 2 ** 10; # 1k limit of chars
my $pr-update-duration = 10 * 60 * 60; # every ten minutes

my $host = '0.0.0.0';
my $port = 60005;
my @suggestions;
my $busy = False;

my Cro::Service $http = Cro::HTTP::Server.new(
    http =&amp;gt; &amp;lt;1.1&amp;gt;,
    :$host,
    :$port,
    application =&amp;gt; routes(),
    after =&amp;gt; [
        Cro::HTTP::Log::File.new(logs =&amp;gt; $*OUT, errors =&amp;gt; $*ERR)
    ]
    );
say strftime(DateTime.now, '%v %R') ~ ': starting up.';

$http.start; # this starts the server part of the application

# the following is an asynchronous structure which listens for events
# then does the block for that event. The main event is to stop 
# the app when a control signal is raised.
react {
    whenever signal(SIGINT) {
        $http.stop;
        say strftime(DateTime.now, '%v %R') ~ ': closing down.';
        done;
    }
    whenever Supply.interval($pr-update-duration) {
        # every pr-update-duration seconds, this block is run
        # it calls the code for raising a PR
        unless $busy {
            $busy = True;
            raise-pr( @suggestions.pop ) while @suggestions;
            $busy = False;
        }
    }
}
# these routes are what define the application
sub routes() {
    route {
        get -&amp;gt; 'suggestion_box' { # the route for the websocket
            web-socket :json, -&amp;gt; $incoming {
                supply whenever $incoming -&amp;gt; $message {
                    my %json = await $message.body;
                    if %json&amp;lt;sha&amp;gt; { # no sha, no play
                        my $response = sanitise( $json );
                            # place limitations on the incoming data
                            # add 'cancel' to ignore data
                        @suggestions.push: $json.hash.clone
                                unless $json&amp;lt;cancel&amp;gt;;
                            # store the data to be sent as PR
                        emit({
                            :timestamp( strftime(DateTime.now, '%v %R')),
                            :$response
                        })
                            # send back to the websocket JSON with
                            # a time stamp and a reponse code
                    }
                    elsif $json&amp;lt;loaded&amp;gt; {
                        # send back a handshake when websocket opens
                        emit({ :connection&amp;lt;Confirmed&amp;gt; })
                    }
                }
            }
        }
    }
}
sub sanitise( %edit --&amp;gt; Str ) {
    my $response = 'OK';
    for %edit.keys {
        when 'editor' { 
            %edit&amp;lt;editor&amp;gt; .= subst(/\W/, '_', :g)
                          .substr( ^21 ) 
        }
        when 'patch' {
            if %edit&amp;lt;patch&amp;gt;.chars &amp;gt; $patch-limit {
                %edit&amp;lt;cancel&amp;gt; = True;
                $response = 'TooManyChanges'
            }
        }
        when 'comment' { %edit&amp;lt;comment&amp;gt; .= substr(^$comment-limit) }
        when &amp;lt;sha repo content&amp;gt;.any  {}
        default       { %edit{ $_ }:delete } 
                   # remove unwanted fields
    }
    $response
}
sub raise-pr( %an-edit ) { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Server code handles all the interaction between the browser and the 'Hallowed Circle'. &lt;/p&gt;

&lt;p&gt;Now we execute the remaining steps ( 2 - 5 ) of the Github sequence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub raise-pr( %edit ) {
    #| Define the secret token. When the container is run,
    #| the token can be passed as an environment parameter. 
    #| Later, we can refactor to obtain it to identify the
    #| user making the edits.
    my $id-token = %*ENV&amp;lt;ID_TOKEN&amp;gt;;
    my $base = 'https://api.github.com/repos';
    # create a descriptive branch name
    my $branch = strftime(DateTime.now, '%v')
            ~ "_{ %edit&amp;lt;editor&amp;gt; }";
    # get the repo information
    my $resp = await Cro::HTTP::Client.get(
        "/{%edit&amp;lt;repo&amp;gt;}/git/ref/heads/main"
    );
    my %data = await $resp.body;
    my $commit = %data&amp;lt;object&amp;gt;&amp;lt;sha&amp;gt;;
    # create a new branch
    $resp = await Cro::HTTP::Client.post(
        "$base/{%edit&amp;lt;repo&amp;gt;}/git/refs",
        content-type =&amp;gt; 'application/vnd.github+json',
        auth =&amp;gt; { bearer =&amp;gt; $id-token },
        headers =&amp;gt; [ X-GitHub-Api-Version =&amp;gt; '2022-11-28' ],
        body =&amp;gt; %(:sha($commit), :ref("refs/heads/$branch"))
    );
    %data = await $resp.body;
    # update file into new branch
    $resp = await Cro::HTTP::Client.put(
        "$base/{%edit&amp;lt;repo&amp;gt;}/contents/{%edit&amp;lt;path&amp;gt;}",
        content-type =&amp;gt; 'application/vnd.github+json',
        auth =&amp;gt; { bearer =&amp;gt; $id-token },
        headers =&amp;gt; [ X-GitHub-Api-Version =&amp;gt; '2022-11-28' ],
        body =&amp;gt; %(
            :sha(%edit&amp;lt;sha&amp;gt;),
            :$branch,
            :content(%edit&amp;lt;content&amp;gt;),
            :message(%edit&amp;lt;comment&amp;gt;),
        )
    );
    %data = await $resp.body;
    # should check to make sure OK
    # Raise a PR for the new branch
    $resp = await Cro::HTTP::Client.post(
        "$base/{%edit&amp;lt;repo&amp;gt;}/pulls",
        content-type =&amp;gt; 'application/vnd.github+json',
        auth =&amp;gt; { bearer =&amp;gt; $id-token },
        headers =&amp;gt; [ X-GitHub-Api-Version =&amp;gt; '2022-11-28' ],
        body =&amp;gt; %(
            :title("Web edit of {%edit&amp;lt;path&amp;gt;}"),
            :head($branch),
            :base&amp;lt;main&amp;gt;,
            :body("Edit suggested by ｢{%edit&amp;lt;editor&amp;gt;}｣ because ｢{%edit&amp;lt;comment&amp;gt;｣}"),
        )
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Github documentation for the PR was particularly confusing because &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;base&lt;/code&gt;, and &lt;code&gt;body&lt;/code&gt; did not seem to be intuitive taken on their own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exiting the wood
&lt;/h2&gt;

&lt;p&gt;I have documented my journey into and out of the woods using as little jargon as possible. My purpose in doing this was to describe it so I could understand it myself, and also in the hope that the gods of the internet (aka search engines) will guide someone else who may have a similar set of issues.&lt;/p&gt;

&lt;p&gt;Naturally, the container is part of a bigger system, and it needs to be tested. But that raises more questions, so I will only be brief.&lt;/p&gt;

&lt;p&gt;It is not so easy to test a websocket. My approach was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to create a custom container for Cro,&lt;/li&gt;
&lt;li&gt;add the service.raku program above.&lt;/li&gt;
&lt;li&gt;The docker container is run locally (using Podman Desktop), so the websocket host is &lt;code&gt;localhost&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A small html file with a websocket and a way to pass the data needed for the suggestion-box is loaded as a file into a browser.&lt;/li&gt;
&lt;li&gt;A small Github repo is created with a file to edit.&lt;/li&gt;
&lt;/ul&gt;

</content>
    <author>
      <name>Richard Hainsworth</name>
    </author>
    <id>https://dev.to/finanalyst/editing-rakudoc-croing-it-to-github-1507</id>
    <published>2025-04-14T20:54:26Z</published>
    <updated>2025-04-14T20:54:26Z</updated>
    <category term="rakulang"/>
    <category term="cro"/>
    <category term="github"/>
  </entry>
  <entry>
    <title>Validating configuration files with Raku and Sparrow Task::Check DSL</title>
    <link rel="alternate" href="https://dev.to/melezhik/validating-config-files-with-raku-and-sparrow-taskcheck-dsl-1ekp" type="text/html"/>
    <content type="html">&lt;p&gt;In real world we have a lot of pure structured or structured in hard to parse formats configuration files:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/etc/default/nginx&lt;/code&gt;, &lt;code&gt;/etc/default/grub&lt;/code&gt;, &lt;code&gt;logrotate.conf&lt;/code&gt;, &lt;code&gt;sysctl.conf&lt;/code&gt; - to name a few. &lt;/p&gt;

&lt;p&gt;In configuration management it's not only important to maintain specific configurations but also validate those changes to make it sure we don't break things.&lt;/p&gt;

&lt;p&gt;Sparrow - is an automation tool written on Raku that allow to make such a validation by leveraging Task::Check DSL rules which underneath are just Raku regular expressions.&lt;/p&gt;

&lt;p&gt;In the rest of this post we take a look at real life example.&lt;/p&gt;




&lt;h1&gt;
  
  
  Grub
&lt;/h1&gt;

&lt;p&gt;Consider linux GRUB boot loader file &lt;code&gt;/etc/default/grub&lt;/code&gt; with following  configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GRUB_DEFAULT=0
#GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=2
GRUB_DISTRIBUTOR=`lsb_release -i -s 2&amp;gt; /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="rootfstype=ext4 quiet splash acpi_osi="
GRUB_CMDLINE_LINUX=""
GRUB_ENABLE_CRYPTODISK=true

# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480

# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"

GRUB_DISABLE_OS_PROBER="true"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Though configuration format is quite simple, based on VAR=value semantics, it still allows some freedom in specification. &lt;/p&gt;

&lt;p&gt;For example to enable variables we could use one of many forms - &lt;code&gt;yes/"yes"&lt;/code&gt;, &lt;code&gt;true/"true"&lt;/code&gt; and just &lt;code&gt;1&lt;/code&gt;. Another challenge is to check that some variable are disabled - they might be just commented or “switched off” via negation form, e.g. VAR=0,false,""&lt;/p&gt;




&lt;p&gt;As rigorous operations we want to validate a couple of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Boot on crypted disks is supported by setting GRUB_ENABLE_CRYPTODISK to one of the values: &lt;code&gt;1,yes,true&lt;/code&gt; and optional quoted form - &lt;code&gt;"yes","true"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OS prober capability is disabled or in other words GRUB_DISABLE_OS_PROBER is not set by using any of forms - &lt;code&gt;1,yes,true,"yes","true"&lt;/code&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before go parsing let's create simple Raku program (Sparrow task), that dumps out configuration removing empty and commented lines, the whole output will be placed inside &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt; markers for visibility:&lt;/p&gt;

&lt;p&gt;task.raku&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!raku&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;validate config {&lt;/span&gt;&lt;span class="si"&gt;$path&lt;/span&gt;&lt;span class="s2"&gt;} ...&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;~~&lt;/span&gt; &lt;span class="sr"&gt;/\S+/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;@out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;~~&lt;/span&gt; &lt;span class="sr"&gt;/^ \s* '#'/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's write verification scenario by creating rules in Sparrow::Task::Check DSL format:&lt;/p&gt;

&lt;p&gt;task.check&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;note: validate config

between: {'&amp;gt;&amp;gt;&amp;gt;'}  {'&amp;lt;&amp;lt;&amp;lt;'}

  note: allow to boot on crypted disks
  regexp: ^^ \s* "GRUB_ENABLE_CRYPTODISK=" (&amp;lt;[y 1 true]&amp;gt;  | '"true"' | '"yes"' )

  note: never allow to enable os prober
  !regexp: ^^ \s* "GRUB_DISABLE_OS_PROBER=" (&amp;lt;[y 1 true]&amp;gt; | '"true"' | '"yes"' )

end:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The DSL code has there major parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;between: {'&amp;gt;&amp;gt;&amp;gt;'}  {'&amp;lt;&amp;lt;&amp;lt;'}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Setting a context for a search in between &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; ... &lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/code&gt; delimiter, this is an example of so called &lt;em&gt;search context modifiers&lt;/em&gt;, in this case - Range modifier. &lt;/p&gt;

&lt;p&gt;In other words this is precaution that we only search within specific boundaries of text output&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;code&gt;regexp: ^^ \s* "GRUB_ENABLE_CRYPTODISK=" (&amp;lt;[y 1 true]&amp;gt;  | '"true"' | '"yes"' )&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verifying that we have &lt;code&gt;GRUB_ENABLE_CRYPTODISK&lt;/code&gt; set to one of values (y,1,true,"true","yes"). &lt;/p&gt;

&lt;p&gt;&lt;code&gt;regexp:&lt;/code&gt; marker means Raku regular expression is used for validation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;note: never allow to enable os prober
!regexp: ^^ \s* "GRUB_DISABLE_OS_PROBER=" (&amp;lt;[y 1 true]&amp;gt; | '"true"' | '"yes"' )&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verifying we DON'T(*) have &lt;code&gt;GRUB_ENABLE_CRYPTODISK&lt;/code&gt; set to one of values (y,1,true,"true","yes"), in other words that GRUB_ENABLE_CRYPTODISK is disabled. &lt;/p&gt;

&lt;p&gt;(*) &lt;code&gt;!&lt;/code&gt; sign before &lt;code&gt;regexp:&lt;/code&gt; marker means negation logic.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Note:&lt;/code&gt; expressions are human readable comments that are showed up in a  report to help us correlate every check to business logic&lt;/p&gt;

&lt;h1&gt;
  
  
  Test report
&lt;/h1&gt;

&lt;p&gt;Now let's run our script and get a result of test. As this is Sparrow scenario, we use &lt;code&gt;s6&lt;/code&gt; - Sparrow CLI runner:&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="c"&gt;#!bash&lt;/span&gt;
s6 &lt;span class="nt"&gt;--task-run&lt;/span&gt; .@path&lt;span class="o"&gt;=&lt;/span&gt;/etc/default/grub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;14:09:20 :: [sparrowtask] - run sparrow task .@path=/etc/default/grub
14:09:20 :: [sparrowtask] - run thing .
[task run: task.raku - .]
[task stdout]
14:09:21 :: validate config examples/grub ...
14:09:21 :: &amp;gt;&amp;gt;&amp;gt;
14:09:21 :: GRUB_CMDLINE_LINUX=""
14:09:21 :: GRUB_CMDLINE_LINUX_DEFAULT="rootfstype=ext4 quiet splash acpi_osi="
14:09:21 :: GRUB_DEFAULT=0
14:09:21 :: GRUB_DISABLE_OS_PROBER="true"
14:09:21 :: GRUB_DISTRIBUTOR=`lsb_release -i -s 2&amp;gt; /dev/null || echo Debian`
14:09:21 :: GRUB_ENABLE_CRYPTODISK=true
14:09:21 :: GRUB_HIDDEN_TIMEOUT_QUIET=true
14:09:21 :: GRUB_TIMEOUT=2
14:09:21 :: &amp;lt;&amp;lt;&amp;lt;
[task check]
# validate config
# allow to boot on crypted disks
stdout match (r) &amp;lt;^^ \s* "GRUB_ENABLE_CRYPTODISK=" (&amp;lt;[y 1 true]&amp;gt;  | '"true"' | '"yes"' )&amp;gt; True
# never allow to enable os prober
stdout match (r) &amp;lt;!^^ \s* "GRUB_DISABLE_OS_PROBER=" (&amp;lt;[y 1 true]&amp;gt; | '"true"' | '"yes"' )&amp;gt; False
=================
TASK CHECK FAIL

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;PS for colorful report please click &lt;a href="https://pasteboard.co/grlUKxSkrGYf.jpg" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expectedly we have following results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GRUB_ENABLE_CRYPTODISK check passed&lt;/li&gt;
&lt;li&gt;GRUB_DISABLE_OS_PROBER fails &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty impressive results considering such a little amount of code has been written!&lt;/p&gt;




&lt;p&gt;Sparrow &lt;a href="https://github.com/melezhik/Sparrow6/blob/master/documentation/taskchecks.md" rel="noopener noreferrer"&gt;Task::Check&lt;/a&gt;s is comprehensive and super flexible tool allowing one to write validation scenarios for arbitrary data formats and complexity, check out documentation pages to know more.&lt;/p&gt;

&lt;p&gt;That is it. Thanks for reading &lt;/p&gt;

</content>
    <author>
      <name>Alexey Melezhik</name>
    </author>
    <id>https://dev.to/melezhik/validating-config-files-with-raku-and-sparrow-taskcheck-dsl-1ekp</id>
    <published>2025-01-30T08:53:50Z</published>
    <updated>2025-01-30T08:53:50Z</updated>
    <category term="rakulang"/>
    <category term="linux"/>
    <category term="grub"/>
    <category term="data"/>
  </entry>
  <entry>
    <title>Useful terminal plugins to build golang code</title>
    <link rel="alternate" href="https://dev.to/melezhik/useful-terminal-plugins-to-build-golang-code-gj0" type="text/html"/>
    <content type="html">&lt;p&gt;Recently, I've released 2 new Sparrow plugins to help build Golang code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sparrowhub.io/plugin/go-build/0.000001" rel="noopener noreferrer"&gt;go-build&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Simple golang code builder&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sparrowhub.io/plugin/go-format/0.000001" rel="noopener noreferrer"&gt;go-format&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Golang code formatter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;They are simple yet useful, providing two essentials tools to build Golang code in terminal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Build code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Format code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of the post shows how to use the plugins&lt;/p&gt;




&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;To install plugins we need to use &lt;a href="https://github.com/melezhik/Tomtit" rel="noopener noreferrer"&gt;Tomtit&lt;/a&gt; task runner with profiles - preset of Raku scenarios that grouped by topics:&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="c"&gt;#!bash&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; /to/you/source/code
tom &lt;span class="nt"&gt;--init&lt;/span&gt; &lt;span class="c"&gt;# initialize Tomtit for the first time&lt;/span&gt;
tom &lt;span class="nt"&gt;--profile&lt;/span&gt; go &lt;span class="c"&gt;# install go profile scenarios&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now once we've installed &lt;code&gt;go&lt;/code&gt; profile, we have an access to &lt;code&gt;go-build&lt;/code&gt;  and &lt;code&gt;go-format&lt;/code&gt; scenarios which are just a Raku wrappers to run mentioned plugins. Code is simple enough and editable to adjust your project specific needs&lt;/p&gt;

&lt;p&gt;Go-build scenario:&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="c"&gt;#!bash&lt;/span&gt;

tom &lt;span class="nt"&gt;--cat&lt;/span&gt; go-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!raku&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cmd/app/main.go&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
  &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cmd/cli/cli.go&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;


&lt;span class="nv"&gt;task&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;run&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;go-build&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$path&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;Go-format scenario:&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="c"&gt;#!bash&lt;/span&gt;

tom &lt;span class="nt"&gt;--cat&lt;/span&gt; go-format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!bash&lt;/span&gt;

task-run &lt;span class="s2"&gt;"go format"&lt;/span&gt;, &lt;span class="s2"&gt;"go-format"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Customization
&lt;/h1&gt;

&lt;p&gt;In case of &lt;code&gt;go-build&lt;/code&gt; scenario - adjust &lt;code&gt;path&lt;/code&gt; array with files to build for your project specific:&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="c"&gt;#!bash&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nano
tom &lt;span class="nt"&gt;--edit&lt;/span&gt; go-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!raku&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cmd/app/app.go&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
  &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cmd/app2/app2.go&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;# the rest of the code stays the same &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Run
&lt;/h1&gt;

&lt;p&gt;To run plugins - use &lt;code&gt;tom&lt;/code&gt; cli runner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!bash
tom go-build
11:56:26 :: go build cmd/main.go
11:56:27 :: cmd/main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!bash
tom go-format
11:57:18 :: cmd/main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;That is it. &lt;/p&gt;

&lt;p&gt;Follow plugins &lt;a href="https://sparrowhub.io/search?q=%27go-%27" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to get familiar with plugins parameters.&lt;/p&gt;

&lt;p&gt;Thanks for reading &lt;/p&gt;

</content>
    <author>
      <name>Alexey Melezhik</name>
    </author>
    <id>https://dev.to/melezhik/useful-terminal-plugins-to-build-golang-code-gj0</id>
    <published>2025-01-24T09:16:01Z</published>
    <updated>2025-01-24T09:16:01Z</updated>
    <category term="rakulang"/>
    <category term="raku"/>
    <category term="go"/>
  </entry>
  <entry>
    <title>A Language a Day</title>
    <link rel="alternate" href="https://andrewshitov.com/2024/11/02/a-language-a-day/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>I published my new book: A Language a Day, which is a collection of brief overviews to 21 programming languages.</p>



<figure class="wp-block-image size-large"><img src="https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-727x1024.jpg" alt="" class="wp-image-7125" srcset="https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-727x1024.jpg 727w, https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-213x300.jpg 213w, https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-768x1082.jpg 768w, https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-1091x1536.jpg 1091w, https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-1454x2048.jpg 1454w, https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-1200x1690.jpg 1200w, https://andrewshitov.com/wp-content/uploads/2024/11/cover-view-scaled.jpg 1818w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px"/></figure>



<p>This book provides a concise overview of 21 different programming languages. Each language is introduced using the same approach: solving several programming problems to showcase its features and capabilities. Languages covered in the book: C++, Clojure, Crystal, D, Dart, Elixir, Factor, Go, Hack, Hy, Io, Julia, Kotlin, Lua, Mercury, Nim, OCaml, Raku, Rust, Scala, and TypeScript.</p>



<p>Each chapter covers the essentials of a different programming language. To make the content more consistent and comparable, I use the same structure for each language, focusing on the following mini projects:</p>



<ol><li><em>Creating a ‘Hello, World!’ program.</em></li><li><em>Implementing a Factorial function using recursion or a functional-style approach.</em></li><li><em>Creating a polymorphic array of objects (a ‘zoo’ of cats and dogs) and calling methods on them.</em></li><li><em>Implementing the Sleep Sort algorithm—while impractical for real-word use, it’s a playful demonstration of language’s concurrency capabilities.</em></li></ol>



<p>Each language description follows—where applicable—this pattern:</p>



<ol><li><em>Installing a command-line compiler and running a program.</em></li><li><em>Creating and using variables.</em></li><li><em>Defining and using functions.</em></li><li><em>Exploring object-oriented features.</em></li><li><em>Handling exception.</em></li><li><em>Introducing basic concurrency and parallelism.</em></li></ol>



<p>You can find all the code examples in this book on GitHub: <a href="https://github.com/ash/a-language-a-day">github.com/ash/a-language-a-day</a>.</p>



<p>You can buy it on Amazon or LeanPub as an electronic or Kindle edition, or as a paper hardcover or paperback version. <a href="https://andrewshitov.com/a-language-a-day/">More information with the links to the shops</a>.</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">I published my new book: A Language a Day, which is a collection of brief overviews to 21 programming languages.</div>
    </summary>
    <author>
      <name>Andrew Shitov</name>
    </author>
    <id>https://andrewshitov.com/?p=7129</id>
    <published>2024-11-02T10:15:02Z</published>
    <updated>2024-11-02T10:15:02Z</updated>
    <category term="Books"/>
    <category term="C++"/>
    <category term="Clojure"/>
    <category term="Crystal"/>
    <category term="D"/>
    <category term="Dart"/>
    <category term="Elixir"/>
    <category term="Elm"/>
    <category term="Factor"/>
    <category term="Go"/>
    <category term="Hack"/>
    <category term="Hy"/>
    <category term="Io"/>
    <category term="Julia"/>
    <category term="Kotlin"/>
    <category term="Lua"/>
    <category term="Mercury"/>
    <category term="Nim"/>
    <category term="OCaml"/>
    <category term="Raku"/>
    <category term="Rust"/>
    <category term="Scala"/>
    <category term="TypeScript"/>
  </entry>
  <entry>
    <title>London Perl &amp; Raku Workshop 2024</title>
    <link rel="alternate" href="https://andrewshitov.com/2024/10/29/london-perl-raku-workshop-2024/" type="text/html"/>
    <content type="html">
&lt;p&gt;Last Saturday, October 26, 2024, another edition of the &lt;a href="https://act.yapc.eu/lpw2024/"&gt;London Perl &amp;amp; Raku Workshop&lt;/a&gt; took place. It was a reopening after a few years break. London Perl Workshop has a long history, started in 2004, so this year it was formally 20 years old.&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0822-1024x677.jpg" alt="" class="wp-image-7104" srcset="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0822-1024x677.jpg 1024w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0822-300x198.jpg 300w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0822-768x507.jpg 768w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0822-1200x793.jpg 1200w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0822.jpg 1500w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /&gt;&lt;/figure&gt;



&lt;h4&gt;The Covid time&lt;/h4&gt;



&lt;p&gt;For me, it was also a Perl-and-or-Raku event after a break. The last in-person event was &lt;a href="https://perlcon.eu/"&gt;PerlCon 2019&lt;/a&gt;, which was an annual European Perl conference that was held in Riga that year. Since then, after the &lt;a href="https://covid.observer"&gt;Covid&lt;/a&gt;’s strike, I have organised a couple of (well, three of them) &lt;a href="https://conf.raku.org"&gt;Raku Conferences&lt;/a&gt;, but that was online in Zoom. Online due to lockdown first, and then due to people slowly reinventing the joy of travel.&lt;/p&gt;



&lt;p&gt;In-between, there were at least two in-person gatherings, another edition of the &lt;a href="http://act.yapc.eu/gpw2024/"&gt;German Perl and Raku Workshop&lt;/a&gt; in April and the &lt;a href="https://tprc.us/tprc-2024-las/"&gt;American Perl and Raku Conference in Las Vegas&lt;/a&gt; in June. I did not attend any of them, but looked at the photos and videos, so I was envy enough because I missed it.&lt;/p&gt;



&lt;h4&gt;To go or not to go&lt;/h4&gt;



&lt;p&gt;You should not forget that right now, right today, at this very moment,  an on-going war against my beloved Ukraine takes place. During the first months, it was not possible to think about anything else, not to mention any entertainment trips or conferences. But time keeps going&amp;#8230; and you see less and less blue-and-yellow flags on the streets. Even at &lt;a href="https://www.waterstones.com"&gt;Waterstones&lt;/a&gt;, the books about that war are located at the very bottom shelves due to the unfortunate nature of alphabetical sorting.&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0627.jpg" alt="" class="wp-image-7072" srcset="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0627.jpg 1000w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0627-300x197.jpg 300w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0627-768x505.jpg 768w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /&gt;&lt;figcaption&gt;From Berlin on top through Russia in the middle to Ukraine at the end of the list.&lt;br&gt;Waterstones in Southampton.&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p&gt;When this year’s London Perl Workshop was announced, I decided to go. Then, I decided not to go. In the end, one week before the event, I thought that I’d better go. Because of my uncertainty, I did not manage to submit a talk on time, so even a small 5-minute lightning talk submission (which I did on the day of the event, ha-ha), did not have a chance to went through. The venue, apparently, was rented until 6pm sharp, and there was no room for anything else.&lt;/p&gt;



&lt;p&gt;So, here are the slides of my talks. I’ve added some comments so that you can enjoy it by following my message.&lt;/p&gt;



&lt;iframe src="https://www.slideshare.net/slideshow/embed_code/key/3m6jmxUJkj9ikz?startSlide=1" width="597" height="486" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px;max-width: 100%;" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;div style="margin-bottom:5px"&gt;&lt;strong&gt;&lt;a href="https://www.slideshare.net/slideshow/perl-jobs-market-in-2024-how-good-is-it/272859502" title="Perl jobs market in 2024, how good is it?" target="_blank" rel="noopener noreferrer"&gt;Perl jobs market in 2024, how good is it?&lt;/a&gt;&lt;/strong&gt; from &lt;strong&gt;&lt;a href="https://www.slideshare.net/andy.sh" target="_blank" rel="noopener noreferrer"&gt;Andrew Shitov&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;



&lt;h4&gt;London and more&lt;/h4&gt;



&lt;p&gt;My journey was quite short, I only had a couple of days in London, but the weather made its present and the plane from Amsterdam landed in Southampton instead. So, I took a chance to see the old walls there and to learn that they offer beans on breakfast at IKEA’s canteen.&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0224-1024x768.jpg" alt="" class="wp-image-7063" srcset="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0224-1024x768.jpg 1024w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0224-300x225.jpg 300w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0224-768x576.jpg 768w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0224-1200x900.jpg 1200w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0224.jpg 1500w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /&gt;&lt;figcaption&gt;Southampton&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p&gt;I really enjoy London, it’s so huge that you fill extremely comfortable in it, how weird that may sound. Despite only a limited couple of days in London, I tried to use the time to wander around just as a tourist. &lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0765-768x1024.jpg" alt="" class="wp-image-7065" srcset="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0765-768x1024.jpg 768w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0765-225x300.jpg 225w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0765-1152x1536.jpg 1152w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0765-1200x1600.jpg 1200w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0765.jpg 1500w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px" /&gt;&lt;/figure&gt;



&lt;p&gt;I also escaped from the middle of the conference day to see the urban life around venue’s location.&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0691-1024x768.jpg" alt="" class="wp-image-7064" srcset="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0691-1024x768.jpg 1024w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0691-300x225.jpg 300w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0691-768x576.jpg 768w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0691-1200x900.jpg 1200w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0691.jpg 1500w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /&gt;&lt;figcaption&gt;Brick Lane Upmarket foodcourt&lt;/figcaption&gt;&lt;/figure&gt;



&lt;h4&gt;Old friends&lt;/h4&gt;



&lt;p&gt;On the day before the conference, I met with an ex-colleague, with whom I worked at two different places, both Perl-related. For a few years, he’s been living in London, and I noticed that he looked so much happier since I last saw him. I hope that is because he lives in this great city now, not because he’s programming in Go, not Perl anymore.&lt;/p&gt;



&lt;p&gt;Of course, I was happy to see people I know from the Perl and/or Raku communities. I did not see most of them at least since 2019, so some of them required a few seconds to recognise me, LOL.&lt;/p&gt;



&lt;h4&gt;The Conference&lt;/h4&gt;



&lt;p&gt;The workshop was really well attended. Even taking into account the significant drop in the numbers since the beginning of 2000s, it was more than 100 people, and there were two full tracks of the talks.&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0714-1024x369.jpg" alt="" class="wp-image-7067" srcset="https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0714-1024x369.jpg 1024w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0714-300x108.jpg 300w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0714-768x277.jpg 768w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0714-1536x554.jpg 1536w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0714-2048x739.jpg 2048w, https://andrewshitov.com/wp-content/uploads/2024/10/IMG_0714-1200x433.jpg 1200w" sizes="(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px" /&gt;&lt;figcaption&gt;In the main room&lt;/figcaption&gt;&lt;/figure&gt;



&lt;p&gt;Let me not list the talks I attended, as the full &lt;a href="https://act.yapc.eu/lpw2024/schedule"&gt;schedule is online&lt;/a&gt;, and the recordings should appear soon.&lt;/p&gt;



&lt;p&gt;There was also a third track, partially filled with regular talks, but partially with a broader-scoped events such as &lt;a href="https://act.yapc.eu/lpw2024/talk/7939"&gt;Science Perl Talks&lt;/a&gt;. I’ve no idea what they talked about there, but it’s somehow connected with the recently-published first issue of the &lt;a href="https://science.perlcommunity.org/spj"&gt;Science Perl Journal&lt;/a&gt; and a &lt;a href="https://www.reddit.com/r/perl/comments/1g4bnx0/unsolicited_email_from_science_perl_committee/"&gt;traditional&lt;/a&gt; &lt;a href="https://www.facebook.com/groups/perlprogrammers/posts/8972284462804262/"&gt;drama&lt;/a&gt; around its establisher.&lt;/p&gt;



&lt;p&gt;But the appearance of the new publication is a good thing in the end. I was also surprised, that in 2024, a &lt;a href="https://allperlbooks.com/year/2024"&gt;few new publications about Perl appeared&lt;/a&gt; or &lt;a href="https://allperlbooks.com/year/2025"&gt;are planned to be published&lt;/a&gt;. I suspect that some of them issued during the previous years are AI-generated texts, but the rest are quite normal and useful books.&lt;/p&gt;



&lt;h4&gt;The Next years&lt;/h4&gt;



&lt;p&gt;There are no decision yet whether there will be another London Perl Workshop in 2025. On the bright side, there should be a soon announcement on the date and location of the German Perl Workshop 2025. Also, there are plans to have a Dutch Perl Workshop 2025 in Utrecht.&lt;/p&gt;



&lt;p&gt;I am thinking of if it’s time to revitalise the annual European Perl and Raku Conference.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This year, there was another London Perl Workshop 2024, I decided to attend it.</div>
    </summary>
    <author>
      <name>Andrew Shitov</name>
    </author>
    <id>https://andrewshitov.com/?p=7058</id>
    <published>2024-10-29T17:59:30Z</published>
    <updated>2024-10-29T17:59:30Z</updated>
    <category term="Conferences"/>
    <category term="Event organising"/>
    <category term="Perl"/>
    <category term="Raku"/>
  </entry>
  <entry>
    <id>https://5ab5traction5.bearblog.dev/introducing-comma-20/</id>
    <title>Introducing Comma 2.0...</title>
    <updated>2024-09-16T12:21:56.078574+00:00</updated>
    <author>
      <name>5ab5traction5</name>
      <email>hidden</email>
    </author>
    <content type="html">&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; There is an issue when opening existing Comma projects that were created in earlier versions. Please use &lt;code&gt;New project from Existing Sources...&lt;/code&gt; rather than &lt;code&gt;Open&lt;/code&gt; and make sure to select &lt;code&gt;Yes&lt;/code&gt; when it prompts you about overwriting an existing &lt;code&gt;.idea&lt;/code&gt; file in the project directory.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This &lt;a href='https://github.com/ab5tract/comma-plugin'&gt;release&lt;/a&gt; represents a major shift for the Comma project in many ways.&lt;/p&gt;
&lt;p&gt;From the bottom of my heart, I want to express the deepest gratitude and thanks to Jonathan Worthington (&lt;code&gt;jnthn++&lt;/code&gt;),
Edument, and all past and future contributors to the Comma project. There's been
so much effort put into this codebase and it was an honor to be able to work on it.&lt;/p&gt;
&lt;p&gt;The most major change is the shift to the &lt;code&gt;IntelliJ Platform Gradle Plugin 2.0&lt;/code&gt;. This
allows Comma to be built (as a plugin) without cloning the
&lt;code&gt;intellij-community&lt;/code&gt; repo and downloading it's entire dependency tree!&lt;/p&gt;
&lt;p&gt;This does seem to preclude building Comma as a standalone IDE, at least for the time being.
That appears to be a different beast entirely and we will have to investigate that as
the time and tuits allow.&lt;/p&gt;
&lt;p&gt;Other major changes included updating the code to correct for broken and (some) deprecated
API changes, as well as the significant cosmetic adjustment of migrating &lt;code&gt;Perl6&lt;/code&gt; to &lt;code&gt;Raku&lt;/code&gt;.
The latter should be almost entirely finished, but there might be some stragglers that I've
missed.&lt;/p&gt;
&lt;p&gt;Building should be as simple as opening this repository in &lt;code&gt;IntelliJ IDEA&lt;/code&gt; (using version &lt;code&gt;2024.2&lt;/code&gt; or greater), and selecting
&lt;code&gt;build &amp;gt; build&lt;/code&gt; from the Gradle build target options. Or, for more immediate gratification, you can select &lt;code&gt;intellij platform &amp;gt; runIde&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; If you don't feel like building it yourself, you can now simply download the &lt;a href='https://github.com/ab5tract/comma-plugin/releases/tag/v2.0-beta.1'&gt;plugin zip from GitHub&lt;/a&gt;. From inside IntelliJ IDEA, open the &lt;code&gt;Settings &amp;gt; Plugins&lt;/code&gt;, find the gear icon, and select &lt;code&gt;Install Plugin from Disk...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enabling the test suite&lt;/li&gt;
&lt;li&gt;Migrating the repository to the Raku organization on github&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Setting up multi-platform releases through CI/CD&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Setting up plugin signing and distribution via the IntelliJ Platform&lt;/li&gt;
&lt;li&gt;Adding NQP as another supported language&lt;/li&gt;
&lt;li&gt;Converting the entire project to Kotlin?&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Your wishlists go here!&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy hacking! :D&lt;/p&gt;
</content>
    <link href="https://5ab5traction5.bearblog.dev/introducing-comma-20/" rel="alternate"/>
    <published>2024-09-14T16:51:00+00:00</published>
  </entry>
  <entry>
    <title>Smuggling Pairs</title>
    <link rel="alternate" href="https://gfldex.wordpress.com/2024/05/28/smuggling-pairs/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>The <a href="https://stackoverflow.com/questions/78520298/how-to-set-a-named-parameter-to-an-exported-sub-when-importing-a-module">question</a> has been raised, how to get named arguments into <code>sub EXPORT</code> via a <code>use</code>-statement. The ever helpful <a href="https://stackoverflow.com/users/1077672/raiph">raiph</a> provided an answer, which in turn left me with the question, why he didn’t just use a <code>Capture</code> to move the data around. Well, because that doesn’t work. The compiler actually evaluates the expression <code>\(:1a, :2b)</code> into <code>(1, 2)</code> before passing it on to <code>EXPORT</code>.</p>



<p>If it’s hard, do it functional!</p>



<pre class="wp-block-code"><code># foo.raku
use v6.d;

constant &amp;transporter = sub { \(:1a, :2b); }
use foo &amp;transporter;

# lib/foo.rakumod
use v6.d;

proto sub EXPORT(|) { * }

multi sub EXPORT(&amp;transporter) {
    &amp;EXPORT(|transporter);
}

multi sub EXPORT(:$a, :$b) {
    dd $a, $b;
    Map.new
}</code></pre>



<p>The idea is to hand a function to <code>use</code> to be called by <code>EXPORT</code>, and then redispatch the value that is produced by that function, to take advantage of Raku´s excellent <a href="https://docs.raku.org/type/Signature">signature binding</a>. The <code>proto</code> and refering to sub <code>EXPORT</code> explicitly is needed because there is also a predefined (and in this case hidden) <code>package</code> called <code>EXPORT</code>.</p>



<p>I’m passing on named arguments to <code>EXPORT</code>, but all kinds of stuff could be returned by <code>&amp;transporter</code>. So long as everything is known pretty early on at compile-time. The <code>use</code>-statement is truly an early bird.</p>



<p/>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">The question has been raised, how to get named arguments into sub EXPORT via a use-statement. The ever helpful raiph provided an answer, which in turn left me with the question, why he didn’t just use a Capture to move the data around. Well, because that doesn’t work. The compiler actually evaluates the expression \(:1a, […]</div>
    </summary>
    <author>
      <name>gfldex</name>
    </author>
    <id>http://gfldex.wordpress.com/?p=3332</id>
    <published>2024-05-28T21:43:11Z</published>
    <updated>2024-05-28T21:43:11Z</updated>
    <category term="Raku"/>
  </entry>
  <entry>
    <title>my $*RAKU++ for -&gt; **@ {};</title>
    <link rel="alternate" href="https://gfldex.wordpress.com/2024/02/25/my-raku-for/" type="text/html"/>
    <content type="html">
&lt;p&gt;As the title states, I made Raku bigger because lol context (that&amp;#8217;s how the &lt;a href="https://github.com/Raku/old-design-docs/blob/master/S29-functions.pod#lol"&gt;Synopsis&lt;/a&gt; is calling &lt;code&gt;**@&lt;/code&gt;) makes supporting feed operators fairly easy. I wonder if Larry added this syntax to &lt;code&gt;Signature&lt;/code&gt; with that goal in mind. With &lt;a href="https://github.com/rakudo/rakudo/pull/5532"&gt;PR#5532&lt;/a&gt; the following becomes possible.&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;&amp;lt;abc bbc cbc&amp;gt; ==&amp;gt; trans('a' =&amp;gt; 'x', 'b' =&amp;gt; 'i') ==&amp;gt; say();&lt;br&gt;# OUTPUT: (xic iic cic)&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Armed with this I can make a script of mine a little simpler.&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;use MONKEY-TYPING;&lt;br&gt;&lt;br&gt;augment class IO::Path {&lt;br&gt;    method trans(|c) {&lt;br&gt;        my $from = self.Str;&lt;br&gt;        my $to = self.Str.trans(|c);&lt;br&gt;&lt;br&gt;        self.rename($to) unless $from eq $to&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;sub rename-whitespace(IO::Path $dir where *.d){&lt;br&gt;    dir($dir).grep({ .d || .f &amp;amp;&amp;amp; .rw })&lt;br&gt;        ==&amp;gt; trans("\c&amp;#091;space]" =&amp;gt; "\c&amp;#091;no-break space]", "\c&amp;#091;apostrophe]" =&amp;gt; "\c&amp;#091;prime]")&lt;br&gt;        ==&amp;gt; sub (*@a) { print '.' for @a}();&lt;br&gt;&lt;br&gt;    dir($dir).grep({ .d &amp;amp;&amp;amp; .rw })».&amp;amp;?ROUTINE;&lt;br&gt;}&lt;br&gt;&lt;br&gt;rename-whitespace('.'.IO);&lt;br&gt;&lt;br&gt;put '';&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;I don&amp;#8217;t like spaces in filenames, as they are often found with audio or video files. Having auto-complete friendly names makes using a CLI less bumpy. By teaching &lt;code&gt;IO::Path&lt;/code&gt; to rename files by providing rules, as they are understood by &lt;code&gt;Str.trans&lt;/code&gt;, I can use a feed operator to get the job done. (I wouldn&amp;#8217;t be surprised to learn, that anonymous subs DWIM here to be emergent behaviour in Raku.)&lt;/p&gt;



&lt;p&gt;Having another PR that adds &lt;code&gt;.trans&lt;/code&gt; to &lt;code&gt;IO::Path&lt;/code&gt; is tempting but requires more thought.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">As the title states, I made Raku bigger because lol context (that’s how the Synopsis is calling **@) makes supporting feed operators fairly easy. I wonder if Larry added this syntax to Signature with that goal in mind. With PR#5532 the following becomes possible. Armed with this I can make a script of mine a […]</div>
    </summary>
    <author>
      <name>gfldex</name>
    </author>
    <id>http://gfldex.wordpress.com/?p=3326</id>
    <published>2024-02-25T15:31:34Z</published>
    <updated>2024-02-25T15:31:34Z</updated>
    <category term="Raku"/>
  </entry>
  <entry>
    <title>Ryuu - a Japanese dragon</title>
    <link rel="alternate" href="https://dev.to/finanalyst/ryuu-a-japanese-dragon-2e7m" type="text/html"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;A follow up to &lt;a href="https://dev.to/finanalyst/creating-a-new-programming-language-draig-503p"&gt;the Welsh dragon&lt;/a&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;p&gt;Firing up another localisation&lt;br&gt;&lt;br&gt;
Steps to Ryuu&lt;br&gt;&lt;br&gt;
Comments on the Raku program&lt;br&gt;&lt;br&gt;
More generally about localisation of coding&lt;br&gt;&lt;br&gt;
If you want to make Ryuu better?  &lt;/p&gt;


&lt;h2&gt;
  
  
  Firing up another localisation
&lt;/h2&gt;

&lt;p&gt;In my previous blog about Y Ddraig, I created a localisation of the Raku Language in Welsh. During a recent conversation, someone mentioned there may be interest in a Japanese localisation, so I thought I would try the same techniques.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I do not speak or read or have ever studied Japanese. The localisation given below will be about as clunky and awkward as any can be. I imagine there may be some hilarious stupidities as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So to be clear, this article is about a proof of concept rather than a real effort to create a production-ready program.&lt;/p&gt;

&lt;p&gt;However, it took me 40 minutes from start to finish, including setting up &lt;a href="https://github.com/finanalyst/rakuast-L10N-JA"&gt;the github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since I like dragons, I named the Japanese cousin to Raku 'Ryuu'. It's a whimsy, not to be treated with much seriousness.&lt;/p&gt;
&lt;h2&gt;
  
  
  Steps to Ryuu
&lt;/h2&gt;

&lt;p&gt;Basically I created a github repo, copied my existing &lt;a href="https://github.com/finanalyst/rakuast-L10N-CY"&gt;Welsh localisation&lt;/a&gt; and changed &lt;strong&gt;CY&lt;/strong&gt; to &lt;strong&gt;JA&lt;/strong&gt;, and &lt;strong&gt;draig&lt;/strong&gt; to &lt;strong&gt;ryuu&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;automation/&lt;/code&gt; directory I used the translation technique explained for Welsh to create the &lt;code&gt;JA&lt;/code&gt; file from the template. The &lt;code&gt;translated.txt&lt;/code&gt; file needed some manual cleaning, because the English word &lt;em&gt;for&lt;/em&gt; has multiple Japanese equivalents. I chose one more or less at random. In addition, Google translate did some strange things to the order of words and numbers in a line.&lt;/p&gt;

&lt;p&gt;After adapting the files in the &lt;code&gt;bin/&lt;/code&gt; directory, and installing the distribution with Raku's &lt;code&gt;zef&lt;/code&gt; utility, I ran &lt;code&gt;tr2ryuu&lt;/code&gt; on the Raku program &lt;code&gt;simple.raku&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A comment about my Welsh blog was that the program in Y Ddraig was not all in Welsh. And here the program is not all in Japanese.&lt;/p&gt;

&lt;p&gt;Remember that the user-facing part of a program will be in the language of the user, in this case it is English. However, the coder-facing part of the program will be in the language of the coder. Below, the coder interface is in Japanese (or rather my ham-fisted attempt at Japanese).&lt;/p&gt;

&lt;p&gt;The following is the result (which I put in a file called simple.ryuu):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;私の $choice;
私の $continue;
私の @bad = &amp;lt;damn stupid nutcase&amp;gt;;
リピート {
    $choice = プロンプト "Type something, like a number, or a string: ";
    言う "You typed in ｢" ~ ($choice ~~ 任意(@bad) ?? "*" × $choice.文字 !! $choice) ~ "｣";
    与えられた $choice {
        いつ "dragon" {
            言う "which is 'draig' in Welsh"
        }
        いつ 任意(@bad) {
            言う "wash your mouth with soap"
        }
        いつ IntStr {
            言う "which evaluates to an integer ", $choice
        }
        いつ RatStr {
            言う "which evaluates to a rational number ", $choice
        }
        デフォルト {
            言う "which does not evaluate to a number "
        }
    }
    $continue = プロンプト "Try again? If not type N: "
} まで $continue 当量 任意(&amp;lt;N n&amp;gt;)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is amazing to me is that when I ran &lt;code&gt;ryuu simple.ryuu&lt;/code&gt;, the program ran without error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comments on the Raku program
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;simple.raku&lt;/code&gt; program is obviously trivial, but what I wanted to show are some interesting Raku features. Note how I created an array of words with &lt;code&gt;@bad = &amp;lt;damn stupid nutcase&amp;gt;;&lt;/code&gt;, and then later I tested to see whether an input word was one of the array elements.&lt;/p&gt;

&lt;p&gt;The Raku idiom &lt;code&gt;いつ 任意(@bad)&lt;/code&gt; or in English &lt;code&gt;when any( @bad )&lt;/code&gt; compares the topic variable, in this case the input value, with each array element and creates a junction of Boolean results. The 'any' effectively &lt;code&gt;or&lt;/code&gt;'s the result to collapse the junction.&lt;/p&gt;

&lt;p&gt;Junctions are not common in programming languages, so I thought if there would be problems, then it would be there. So I was surprised to find my Raku program works without error in another language.&lt;/p&gt;

&lt;h2&gt;
  
  
  More generally about localisation of coding
&lt;/h2&gt;

&lt;p&gt;All the major coding languages are in English. There are, however, coders from all over the world, and the majority of those from non-English speaking nations would have needed to learn English before (or at the same time as) they learnt coding.&lt;/p&gt;

&lt;p&gt;We are thus creating a new technological elite: those who can understand English (or some subset of it), and those who cannot. The more coding becomes an essential part of life, the greater the ability divide between coders (who speak English) and non-coders will become.&lt;/p&gt;

&lt;p&gt;The aim of localising a programming language is to provide an entry into coding in a form that is more accessible to every human being, whatever their natural language.&lt;/p&gt;

&lt;p&gt;However, the aim of this approach is not to eliminate English at every level of complexity, but to provide a sufficiently rich language for most normal coding and educational needs.&lt;/p&gt;

&lt;p&gt;In addition, by having a canonical language (Raku, which is based on English) into which all localised languages can be translated, what we get is a universal auxiliary language together with a universality of being able to code.&lt;/p&gt;

&lt;p&gt;Having a single auxiliary language means that a non-English speaking person writing in a localised coding language can translate the program with the problem into Raku, have a developer on the other side of the globe find the problem, and suggest a solution in code, then for that solution to be translated back into the local language.&lt;/p&gt;

&lt;p&gt;Naturally, a person who wants to learn more about coding, or who needs to delve deeper into the workings of a module, will need to learn English. Learning wider to learn deeper is a normal part of the educational experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to make Ryuu better?
&lt;/h2&gt;

&lt;p&gt;Ryuu or however it should be called, absolutely is in need of Tender loving care. Please feel free to use the github issues or PR processes to suggest better translations.&lt;/p&gt;

&lt;p&gt;At some stage, Ryuu will join the official Raku localisations.&lt;/p&gt;

</content>
    <author>
      <name>Richard Hainsworth</name>
    </author>
    <id>https://dev.to/finanalyst/ryuu-a-japanese-dragon-2e7m</id>
    <published>2024-01-30T18:30:58Z</published>
    <updated>2024-01-30T18:30:58Z</updated>
    <category term="rakulang"/>
    <category term="l10n"/>
    <category term="japanese"/>
  </entry>
  <entry>
    <title>Autoarraying</title>
    <link rel="alternate" href="https://gfldex.wordpress.com/2023/12/25/autoarraying/" type="text/html"/>
    <content type="html">
&lt;p&gt;Over on Reddit &lt;a href="https://www.reddit.com/user/zeekar/"&gt;zeekar&lt;/a&gt; wasn&amp;#8217;t too happy about Raku&amp;#8217;s love of &lt;code&gt;Seq&lt;/code&gt;. It&amp;#8217;s immutability can be hindering indeed.&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;my @nums = &amp;#091; &amp;#091;1..10], ];&lt;br&gt;@nums&amp;#091;0] .= grep: * % 2;&lt;br&gt;@nums&amp;#091;0].push(11); # We can't push to a Seq.&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;I provided a &lt;a href="https://www.reddit.com/r/rakulang/comments/18pv92o/better_way_to_deal_with_nested_arrays_losing/"&gt;solution&lt;/a&gt; I wasn&amp;#8217;t happy with. It doesn&amp;#8217;t DWIM and is anything but elegant. So while heavily digesting on my sofa (it is this time of the year), the problem kept rolling around in my head. At first I wanted to wrap &lt;code&gt;Array.grep()&lt;/code&gt;, but that would be rather intrusive and likely break Rakudo itself. After quite a bit of thinking, I ended up with the question. How can I have indexable container (aka Array) that will turn each value on assignment into an (sub-)Array?&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;my Array() @foo = &amp;#091; 1..10, ];&lt;br&gt;dd @foo;&lt;br&gt;# Array&amp;#091;Array(Any)] @foo = Array&amp;#091;Array(Any)].new($&amp;#091;1, 2, 3, 4, 5, 6, 7, 8, 9, 10])&lt;br&gt;@foo&amp;#091;0] .= grep: * % 2;&lt;br&gt;@foo&amp;#091;1] = 42;&lt;br&gt;dd @foo;&lt;br&gt;# Array&amp;#091;Array(Any)] @foo = Array&amp;#091;Array(Any)].new($&amp;#091;1, 3, 5, 7, 9], $&amp;#091;42])&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The answer is obvious. By telling the compiler what I want! Coersion-types have become really hard to distinguish from magic.&lt;/p&gt;



&lt;p&gt;I wish you all a Merry Christmas and the very best questions for 2024.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Over on Reddit zeekar wasn’t too happy about Raku’s love of Seq. It’s immutability can be hindering indeed. I provided a solution I wasn’t happy with. It doesn’t DWIM and is anything but elegant. So while heavily digesting on my sofa (it is this time of the year), the problem kept rolling around in my […]</div>
    </summary>
    <author>
      <name>gfldex</name>
    </author>
    <id>http://gfldex.wordpress.com/?p=3314</id>
    <published>2023-12-25T08:57:55Z</published>
    <updated>2023-12-25T08:57:55Z</updated>
    <category term="Raku"/>
  </entry>
  <entry>
    <id>https://5ab5traction5.bearblog.dev/an-initial-investigation-into-using-zig-to-speed-up-raku-code/</id>
    <title>An initial investigation into using Zig to speed up Raku code</title>
    <updated>2023-11-28T12:33:34.347658+00:00</updated>
    <author>
      <name>5ab5traction5</name>
      <email>hidden</email>
    </author>
    <content type="html">&lt;p&gt;&lt;em&gt;Note: This post is also &lt;a href='https://gist.github.com/ab5tract/61e08cfaf0bb3e67b3a3dc009fa3cc7a#file-run-notes-md'&gt;available as a gist&lt;/a&gt; if you find that format more readable.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=introduction&gt;Introduction&lt;/h2&gt;&lt;p&gt;This research was conducted while preparing an upcoming &lt;a href='https://raku-advent.blog/'&gt;Raku Advent Calendar&lt;/a&gt; post. The Raku code uses a basic supply pipeline to feed &lt;code&gt;$volume&lt;/code&gt; objects through a validation stage that requires a CRC32 check before going to the output sink, which prints the processing time of the validation stage.&lt;/p&gt;
&lt;p&gt;The "reaction graph" is designed to simulate a stream processing flow, where inputs arrive and depart via Candycane™ queues (that's the name of Santa's Workshop Software's queueing service, in case you weren't familiar).&lt;/p&gt;
&lt;p&gt;The entire scenario is contrived in that CRC32 was chosen due to native implementation availability in both Raku and Zig, allowing comparison. It's not an endorsement of using CRC32 in address validation to deliver Santa's, or anyone's, packages.&lt;/p&gt;
&lt;p&gt;Also, thanks to the very helpful folks at &lt;a href='https://ziggit.dev'&gt;ziggit.dev&lt;/a&gt; for answering my &lt;a href='https://ziggit.dev/t/heap-allocation-without-a-main-function/2249/6'&gt;newbie question&lt;/a&gt; in depth.&lt;/p&gt;
&lt;h2 id=methodology&gt;Methodology&lt;/h2&gt;&lt;p&gt;The source code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Raku - &lt;a href='https://gist.github.com/ab5tract/61e08cfaf0bb3e67b3a3dc009fa3cc7a#file-crc-getter-raku'&gt;crc-getter.raku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Raku+Zig - &lt;a href='https://gist.github.com/ab5tract/61e08cfaf0bb3e67b3a3dc009fa3cc7a#file-crc-getter-extended-raku'&gt;crc-getter-extended.raku&lt;/a&gt;, &lt;a href='https://gist.github.com/ab5tract/61e08cfaf0bb3e67b3a3dc009fa3cc7a#file-main-zig'&gt;main.zig&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At larger volumes, Raku struggles with the initialization speed of the &lt;code&gt;$volume&lt;/code&gt; objects that are instantiated. I replaced the native Raku class with one written in Zig, using the &lt;code&gt;is repr('CStruct')&lt;/code&gt; trait in Raku and the &lt;code&gt;extern struct&lt;/code&gt; qualifier in Zig.&lt;/p&gt;
&lt;p&gt;In Zig I use a combination of an arena allocator (for the string passed from Raku) and a memory pool (designed to quicklymake  copies of a single type, exactly fitting our use case) to construct &lt;code&gt;Package&lt;/code&gt; objects.&lt;/p&gt;
&lt;p&gt;Additionally, for Raku+Zig the CRC32 hashing routine from Zig's &lt;code&gt;stdlib&lt;/code&gt; is used via a tiny wrapper function.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;--bad-packages&lt;/code&gt; option is provided by both Raku scripts, which makes 10% of the objects have a mismatched address/CRC32 pair.&lt;/p&gt;
&lt;p&gt;The library tested was compiled with &lt;code&gt;-Doptimize=ReleaseFast&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Batches are repeated &lt;code&gt;$batch&lt;/code&gt; times, which defaults to 5.&lt;/p&gt;
&lt;p&gt;All results from an M2 MacBook Pro.&lt;/p&gt;
&lt;h3 id=caveats&gt;Caveats&lt;/h3&gt;&lt;p&gt;This test and its is only intended to reflect the case where an object is constructed in Zig based on input from Raku. It is not intended to be a test of Zig's native speed in the creation of structs.&lt;/p&gt;
&lt;p&gt;There is a call to &lt;code&gt;sleep&lt;/code&gt; that gives time -- &lt;code&gt;0.001&lt;/code&gt; seconds --  to get the &lt;code&gt;react&lt;/code&gt; block up and running before emitting the first &lt;code&gt;True&lt;/code&gt; on the &lt;code&gt;$ticker-supplier&lt;/code&gt;. This affects overall runtime but &lt;em&gt;not&lt;/em&gt; the batch or initialization metrics.&lt;/p&gt;
&lt;p&gt;The speed of Raku+Zig was so fast that the tool used to measure these details (&lt;code&gt;cmdbench&lt;/code&gt;) could not find results in &lt;code&gt;ps&lt;/code&gt; for the execution because it had already finished. These are marked as &lt;code&gt;Unmeasured&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the next iteration of this research, there sould be two additional entries in the data tables below for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Raku+Zig: Raku-managed objects / Zig crc32&lt;/li&gt;
&lt;li&gt;Raku+Zig: Zig-managed objects / Raku crc32&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=results&gt;Results&lt;/h2&gt;&lt;h3 id=10000&gt;10,000&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Volume&lt;/th&gt;
  &lt;th&gt;Edition&lt;/th&gt;
  &lt;th&gt;Runtime&lt;/th&gt;
  &lt;th&gt;Batch Time&lt;/th&gt;
  &lt;th&gt;Initialization&lt;/th&gt;
  &lt;th&gt;Max bytes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;10,000&lt;/td&gt;
  &lt;td&gt;Raku&lt;/td&gt;
  &lt;td&gt;1.072s&lt;/td&gt;
  &lt;td&gt;1: 0.146596686s&lt;br /&gt;2: 0.138983732s&lt;br /&gt;3: 0.142380065s&lt;br /&gt;4: 0.136050775s&lt;br /&gt;5: 0.134760525s&lt;/td&gt;
  &lt;td&gt;0.008991746s&lt;/td&gt;
  &lt;td&gt;180240384&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;10,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;/td&gt;
  &lt;td&gt;0.44s&lt;/td&gt;
  &lt;td&gt;1: 0.010978411s&lt;br /&gt;2: 0.006575705s&lt;br /&gt;3: 0.004145623s&lt;br /&gt;4: 0.004280415s&lt;br /&gt;5: 0.00468929s&lt;/td&gt;
  &lt;td&gt;0.020358033s&lt;/td&gt;
  &lt;td&gt;&lt;code&gt;Unmeasured&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;10,000&lt;/td&gt;
  &lt;td&gt;Raku&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;1.112s&lt;/td&gt;
  &lt;td&gt;1: 0.157788932s&lt;br /&gt;2: 0.149544686s&lt;br /&gt;3: 0.156293433s&lt;br /&gt;4: 0.151365477s&lt;br /&gt;5: 0.147947436s&lt;/td&gt;
  &lt;td&gt;0.008059955s&lt;/td&gt;
  &lt;td&gt;196263936&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;10,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;0.463s&lt;/td&gt;
  &lt;td&gt;1: 0.031300276s&lt;br /&gt;2: 0.01006562s&lt;br /&gt;3: 0.010693328s&lt;br /&gt;4: 0.011056994s&lt;br /&gt;5: 0.010770828s&lt;/td&gt;
  &lt;td&gt;0.010954495s&lt;/td&gt;
  &lt;td&gt;&lt;code&gt;Unmeasured&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=notes&gt;Notes&lt;/h4&gt;&lt;p&gt;The Raku+Zig solution wins in performance, but loses the initialization race. Raku is doing a decent showing in comparison to how far it has come performance-wise.&lt;/p&gt;
&lt;h3 id=100000&gt;100,000&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Volume&lt;/th&gt;
  &lt;th&gt;Edition&lt;/th&gt;
  &lt;th&gt;Overall&lt;/th&gt;
  &lt;th&gt;Batch Time&lt;/th&gt;
  &lt;th&gt;Initialization&lt;/th&gt;
  &lt;th&gt;Max bytes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;100,000&lt;/td&gt;
  &lt;td&gt;Raku&lt;/td&gt;
  &lt;td&gt;7.163s&lt;/td&gt;
  &lt;td&gt;1: 1.360029456s&lt;br /&gt;2: 1.32534014s&lt;br /&gt;3: 1.353072834s&lt;br /&gt;4: 1.346668338s&lt;br /&gt;5: 1.351110502s&lt;/td&gt;
  &lt;td&gt;0.062402473s&lt;/td&gt;
  &lt;td&gt;210173952&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;100,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;/td&gt;
  &lt;td&gt;0.75s&lt;/td&gt;
  &lt;td&gt;1: 0.079802007s&lt;br /&gt;2: 0.073638176s&lt;br /&gt;3: 0.053291894s&lt;br /&gt;4: 0.05087652s&lt;br /&gt;5: 0.050394687s&lt;/td&gt;
  &lt;td&gt;0.05855585s&lt;/td&gt;
  &lt;td&gt;241205248&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;100,000&lt;/td&gt;
  &lt;td&gt;Raku&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;7.89s&lt;/td&gt;
  &lt;td&gt;1: 1.496982355s&lt;br /&gt;2: 1.484494027s&lt;br /&gt;3: 1.497365023s&lt;br /&gt;4: 1.490810525s&lt;br /&gt;5: 1.492416774s&lt;/td&gt;
  &lt;td&gt;0.060026016s&lt;/td&gt;
  &lt;td&gt;209403904&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;100,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;1.076s&lt;/td&gt;
  &lt;td&gt;1: 0.16960934s&lt;br /&gt;2: 0.111172493s&lt;br /&gt;3: 0.110844786s&lt;br /&gt;4: 0.113021202s&lt;br /&gt;5: 0.111713535s&lt;/td&gt;
  &lt;td&gt;0.051436311s&lt;/td&gt;
  &lt;td&gt;242450432&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=notes-1&gt;Notes&lt;/h4&gt;&lt;p&gt;We see Raku+Zig take first place in everything but memory consumption, which we can assume is a function of using the NativeCall bridge, not to mention my new-ness as a Zig programmer.&lt;/p&gt;
&lt;h3 id=1000000&gt;1,000,000&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Volume&lt;/th&gt;
  &lt;th&gt;Edition&lt;/th&gt;
  &lt;th&gt;Overall&lt;/th&gt;
  &lt;th&gt;Batch Time&lt;/th&gt;
  &lt;th&gt;Initialization&lt;/th&gt;
  &lt;th&gt;Max bytes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;1,000,000&lt;/td&gt;
  &lt;td&gt;Raku&lt;/td&gt;
  &lt;td&gt;68.081s&lt;/td&gt;
  &lt;td&gt;1: 13.475302627s&lt;br /&gt;2: 13.161153845s&lt;br /&gt;3: 13.293998956s&lt;br /&gt;4: 13.364662217s&lt;br /&gt;5: 13.474755295s&lt;/td&gt;
  &lt;td&gt;0.95481884s&lt;/td&gt;
  &lt;td&gt;417103872&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;1,000,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;/td&gt;
  &lt;td&gt;3.758s&lt;/td&gt;
  &lt;td&gt;1: 0.788083286s&lt;br /&gt;2: 0.509883905s&lt;br /&gt;3: 0.492898873s&lt;br /&gt;4: 0.500868284s&lt;br /&gt;5: 0.498677495s&lt;/td&gt;
  &lt;td&gt;0.575087671s&lt;/td&gt;
  &lt;td&gt;514064384&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;1,000,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;75.796s&lt;/td&gt;
  &lt;td&gt;1: 14.940173822s&lt;br /&gt;2: 14.632683637s&lt;br /&gt;3: 14.866796226s&lt;br /&gt;4: 15.272903792s&lt;br /&gt;5: 15.027481448s&lt;/td&gt;
  &lt;td&gt;0.704549212s&lt;/td&gt;
  &lt;td&gt;396656640&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;1,000,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;6.553s&lt;/td&gt;
  &lt;td&gt;1: 1.362189763s&lt;br /&gt;2: 1.061496504s&lt;br /&gt;3: 1.069134685s&lt;br /&gt;4: 1.062746049s&lt;br /&gt;5: 1.061096044s&lt;/td&gt;
  &lt;td&gt;0.528011288s&lt;/td&gt;
  &lt;td&gt;462766080&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=notes-2&gt;Notes&lt;/h4&gt;&lt;p&gt;Raku's native CRC32 performance is clearly lagging here. Raku+Zig keeps its domination except in the realm of memory usage. It would be hard to justify using the Raku native version strictly on its reduced memory usage, considering the performance advantage on display here&lt;/p&gt;
&lt;p&gt;A "slow first batch" problem begins to affect Raku+Zig. Running with &lt;code&gt;bad-packages&lt;/code&gt; enabled slows down the Raku+Zig crc32 loop, hinting that there might be some optimizations on either the Raku or the Zig/clang side of things that can't kick in when the looped data is heterogenous.&lt;/p&gt;
&lt;p&gt;Dynamic runtime optimization &lt;em&gt;sounds&lt;/em&gt; more like a Rakudo thing than a Zig thing, though.&lt;/p&gt;
&lt;h3 id=10000000&gt;10,000,000&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Volume&lt;/th&gt;
  &lt;th&gt;Edition&lt;/th&gt;
  &lt;th&gt;Runtime&lt;/th&gt;
  &lt;th&gt;Batch Time&lt;/th&gt;
  &lt;th&gt;Initialization&lt;/th&gt;
  &lt;th&gt;Max bytes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;10,000,000&lt;/td&gt;
  &lt;td&gt;Raku&lt;/td&gt;
  &lt;td&gt;704.852s&lt;/td&gt;
  &lt;td&gt;1: 136.588638184s&lt;br /&gt;2: 136.851019628s&lt;br /&gt;3: 138.44696743s&lt;br /&gt;4: 139.777040922s&lt;br /&gt;5: 139.490784317s&lt;/td&gt;
  &lt;td&gt;13.299274221s&lt;/td&gt;
  &lt;td&gt;2055012352&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;10,000,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;/td&gt;
  &lt;td&gt;38.505s&lt;/td&gt;
  &lt;td&gt;1: 8.843459877s&lt;br /&gt;2: 4.84300835s&lt;br /&gt;3: 4.991842433s&lt;br /&gt;4: 5.077245603s&lt;br /&gt;5: 4.939533707s&lt;/td&gt;
  &lt;td&gt;9.375436134s&lt;/td&gt;
  &lt;td&gt;2881126400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;10,000,000&lt;/td&gt;
  &lt;td&gt;Raku&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;792.1s&lt;/td&gt;
  &lt;td&gt;1: 162.333803401s&lt;br /&gt;2: 174.815386318s&lt;br /&gt;3: 168.299796081s&lt;br /&gt;4: 162.643428135s&lt;br /&gt;5: 163.205406678s&lt;/td&gt;
  &lt;td&gt;10.252639311s&lt;/td&gt;
  &lt;td&gt;2124267520&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;10,000,000&lt;/td&gt;
  &lt;td&gt;Raku+Zig&lt;br /&gt;(&lt;code&gt;bad-packages&lt;/code&gt;)&lt;/td&gt;
  &lt;td&gt;65.174&lt;/td&gt;
  &lt;td&gt;1: 14.41616445s&lt;br /&gt;2: 11.078961309s&lt;br /&gt;3: 10.662389991s&lt;br /&gt;4: 11.20240076s&lt;br /&gt;5: 10.614430063s&lt;/td&gt;
  &lt;td&gt;6.778600235s&lt;/td&gt;
  &lt;td&gt;2861596672&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=notes-3&gt;Notes&lt;/h4&gt;&lt;p&gt;Pure Raku &lt;em&gt;really&lt;/em&gt; struggles with a volume of this order of magnitude. But if you add in just a little bit of Zig, you can reasonably supercharge Raku's capabilities.&lt;/p&gt;
&lt;p&gt;The "slow first batch" for Raku+Zig has been appearing in more understated forms in other tests. Here the first batch is over double the runtime of the second batch. What is causing this?&lt;/p&gt;
&lt;h3 id=100000000&gt;100,000,000&lt;/h3&gt;&lt;p&gt;This doesn't seem to work. At least, I'm not patient enough. The process seems to stall, growing and shrinking memory but never finishing.&lt;/p&gt;
&lt;h2 id=final-thoughts&gt;Final Thoughts&lt;/h2&gt;&lt;p&gt;This is a preliminary report in blog post form based on a contrived code sample written for another, entirely different blog post. More data and deeper analysis will have to come later.&lt;/p&gt;
&lt;p&gt;Zig's C ABI compatibility is clearly no put on. It works seamlessly with Raku's NativeCall. Granted, we haven't really pushed the boundaries of what the C ABI can look like but one of the core takeaways is actually that &lt;em&gt;with Zig we can design that interface&lt;/em&gt;. In other words, we are in charge of how ugly, or not, it gets. Considering how dead simple the &lt;code&gt;extern struct &amp;lt;-&amp;gt; is repr('CStruct')&lt;/code&gt; support is, I don't think the function signatures need to get nearly as gnarly as they get in C.&lt;/p&gt;
&lt;p&gt;Sussing the truth of that supposition out will take some time and effort in learning Zig. I'm looking forward to it. My first stop will probably be a JSON library that uses Zig. I'm also going to be looking into using Zig as the compiler for Rakudo, as it might simplify our releases significantly.&lt;/p&gt;
</content>
    <link href="https://5ab5traction5.bearblog.dev/an-initial-investigation-into-using-zig-to-speed-up-raku-code/" rel="alternate"/>
    <published>2023-11-27T14:21:37.120190+00:00</published>
  </entry>
  <entry>
    <title>Missing Virtuousness</title>
    <link rel="alternate" href="https://gfldex.wordpress.com/2023/11/10/missing-virtuousness/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>According to Larry, laziness is a programmers virtue. The best way to be lazy is having somebody else do it. By my <a href="https://ieji.de/@gfldex/111366016310683643">request</a>, <a href="https://fosstodon.org/@smokemachine/">SmokeMachine</a> kindly <a href="https://github.com/FCO/HTML-Component/commit/89a4236ef9bbd9a0260883d3282c28889fd21e8f">did</a> so. This is not fair. We both should have been lazy and offload the burden to the CORE-team.</p>



<p>Please consider the following code.</p>



<pre class="wp-block-code"><code>my @many-things = (1..10).List;
sub doing-one-thing-at-a-time($foo) { ... }
say doing-one-thing-at-a-time(@many-things.all);</code></pre>



<p>Rakudo goes out of it’s way to create the illusion that <code>sub doing-one-thing-at-a-time</code> can deal with a <code>Junction</code>. It can’t, the dispatcher does all the work of running code in parallel. There are tricks we can play to untangle a <code>Junction</code>, but there is no guarantee that all values are produced. <code>Junction</code>s are allowed to short-circuit.</p>



<p>This was bouncing around in my head for quite some time, until it collided with my thoughts about <code>Range</code>. We may be handling <code>HyperSeq</code> and <code>RaceSeq</code> wrong.</p>



<pre class="wp-block-code"><code>my @many-things = (1..10).List;
sub doing-one-thing-at-a-time($foo) { ... }
say doing-one-thing-at-a-time(@many-tings.<strong>hyper(:degree&lt;10&gt;)</strong>);</code></pre>



<p>As with <code>Junction</code>s doing dispatch-magic to make hyper/race just work, moving the handling to the dispatcher would move the decision from the callee to the caller and, as such, from the author of a module to the user. We can do that by hand already with <code>.hyper.grep(*.foo)</code> or other forms of boilerplate. In Raku-land we should be able to do better and provide a generalisation of transforming calls with the help of the dispatcher.</p>



<p>I now know what to ask Santa for this year.</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">According to Larry, laziness is a programmers virtue. The best way to be lazy is having somebody else do it. By my request, SmokeMachine kindly did so. This is not fair. We both should have been lazy and offload the burden to the CORE-team. Please consider the following code. Rakudo goes out of it’s way […]</div>
    </summary>
    <author>
      <name>gfldex</name>
    </author>
    <id>http://gfldex.wordpress.com/?p=3308</id>
    <published>2023-11-10T12:43:35Z</published>
    <updated>2023-11-10T12:43:35Z</updated>
    <category term="Raku"/>
  </entry>
  <entry>
    <title type="html">JSON::Class:auth Released</title>
    <link href="https://vrurg.github.io/2023/10/31/json-class-released" rel="alternate" type="text/html" title="JSON::Class:auth Released"/>
    <published>2023-10-31T00:00:00-04:00</published>
    <updated>2023-10-31T00:00:00-04:00</updated>
    <id>https://vrurg.github.io/2023/10/31/json-class-released</id>
    <content type="html" xml:base="https://vrurg.github.io/2023/10/31/json-class-released"><![CDATA[<p>My version of <code class="language-plaintext highlighter-rouge">JSON::Class</code> is now released. <a href="/2023/10/17/new-json-class">The previous post</a> explains why does this worth a note.</p>]]></content>
    <author>
      <name>Vadim Belman</name>
    </author>
    <category term="Raku"/>
    <category term="JSON"/>
    <category term="serialization"/>
    <category term="module"/>
    <summary type="html"><![CDATA[My version of JSON::Class is now released. The previous post explains why does this worth a note.]]></summary>
  </entry>
  <entry>
    <title>Incomplete Ranges</title>
    <link rel="alternate" href="https://gfldex.wordpress.com/2023/10/24/incomplete-ranges/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>Lately, some <a href="https://github.com/Raku/problem-solving/issues/391">unhappiness</a> has popped up about <code>Range</code> and it’s incomplete numericaliness. Having just one <a href="https://rakujourney.wordpress.com/2023/10/24/raku-home-on-the-range/">blogpost</a> about it is clearly not enough, given how big <code>Range</code>s can be.</p>



<pre class="wp-block-code"><code>say (-∞..∞).elems;
# Cannot .elems a lazy list
  in block &lt;unit&gt; at tmp/2021-03-08.raku line 2629</code></pre>



<p>I don’t quite agree with Rakudo here. There are clearly ∞ elements in that lazy list. This could very well be special-cased.</p>



<p>The argument has been made, that many operators in Raku tell you what type the returned value will have. Is that so? (This question is always silly or unnecessary.)</p>



<pre class="wp-block-code"><code>say (1 + 2&amp;3).WHAT;
# (Junction)</code></pre>



<p>Granted, <code>Junction</code> is quite special. But so are <code>Range</code>s. Yet, Raku covers the former everywhere but the latter feels uncompleted. Please consider the following code.</p>



<pre class="wp-block-code"><code>multi sub infix:&lt;±&gt;(Numeric \n, Numeric \variance --&gt; Range) {
    (n - variance) .. (n + variance)
}

say 2.6 &gt; 2 ± 0.5;
# True

my @heavy-or-light = 25.6, 50.3, 75.4, 88.8;

@heavy-or-light.map({ $_ ≤ 75 ± 0.5 ?? „$_ is light“ !! „$_ is heavy“ }).say;
# (25.6 is heavy 50.3 is heavy 75.4 is heavy 88.8 is heavy)</code></pre>



<p>To me that looks like it should DWIM. It doesn’t, because <code>&amp;infix:«≤»</code> defaults to coercing to <code>Real</code> and then comparing numerically.</p>



<p>This could easily be fixed by adding a few more multis and I don’t think it would break any production code. We already provide quite a few good tools for scientists. And those scientists do love their error bars — which are ranges. I would love for them to have another reason to use Raku over … that other language.</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Lately, some unhappiness has popped up about Range and it’s incomplete numericaliness. Having just one blogpost about it is clearly not enough, given how big Ranges can be. I don’t quite agree with Rakudo here. There are clearly ∞ elements in that lazy list. This could very well be special-cased. The argument has been made, […]</div>
    </summary>
    <author>
      <name>gfldex</name>
    </author>
    <id>http://gfldex.wordpress.com/?p=3298</id>
    <published>2023-10-24T19:36:17Z</published>
    <updated>2023-10-24T19:36:17Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title type="html">A New JSON::Class Module. All New.</title>
    <link href="https://vrurg.github.io/2023/10/17/new-json-class" rel="alternate" type="text/html" title="A New JSON::Class Module. All New."/>
    <published>2023-10-17T00:00:00-04:00</published>
    <updated>2023-10-17T00:00:00-04:00</updated>
    <id>https://vrurg.github.io/2023/10/17/new-json-class</id>
    <content type="html" xml:base="https://vrurg.github.io/2023/10/17/new-json-class"><![CDATA[<p>This will be a short one. I have recently released a family of <code class="language-plaintext highlighter-rouge">WWW::GCloud</code> modules for accessing Google Cloud services. Their REST API is, apparently, JSON-based. So, I made use of the existing <a href="https://raku.land/zef:jonathanstowe/JSON::Class"><code class="language-plaintext highlighter-rouge">JSON::Class</code></a>. Unfortunately, it was missing some features critically needed for my work project. I implemented a couple of workarounds, but still felt like it’s not the way it has to be. Something akin to <a href="https://raku.land/zef:vrurg/LibXML::Class"><code class="language-plaintext highlighter-rouge">LibXML::Class</code></a> would be great to have…</p>

<p>There was a big “but” in this. We already have <a href="https://raku.land/?q=XML%3A%3AClass"><code class="language-plaintext highlighter-rouge">XML::Class</code></a>, <code class="language-plaintext highlighter-rouge">LibXML::Class</code>, and the current <code class="language-plaintext highlighter-rouge">JSON::Class</code>. All are responsible for doing basically the same thing: de-/serializing classes. If I wanted another JSON serializer then I had to take into account that <code class="language-plaintext highlighter-rouge">JSON::Class</code> is already taken. There are three ways to deal with it:</p>

<ol>
  <li>Branch the current <code class="language-plaintext highlighter-rouge">JSON::Class</code> and re-implement it as a backward-incompatible version.</li>
  <li>Give the new module a different name.</li>
  <li>Implement own version and publish it under my name.</li>
</ol>

<p>The first two options didn’t appeal to me. The third one is now about to happen.</p>

<p>I expect it to be a stress-test for Raku ecosystem as, up to my knowledge, it’s going to be the first case where two different modules share the same name but not publishers.</p>

<p>As a little reminder:</p>

<ul>
  <li>To use the old module one would have to have <code class="language-plaintext highlighter-rouge">JSON::Class:auth&lt;zef:jonathanstowe&gt;</code> in their dependencies and, perhaps, in their <code class="language-plaintext highlighter-rouge">use</code> statement.</li>
  <li>The new module will be available as <code class="language-plaintext highlighter-rouge">JSON::Class:auth&lt;zef:vrurg&gt;</code>.</li>
</ul>

<p>There is still some time before I publish it because the documentation is not ready yet.</p>

<p>Let’s 🤞🏻.</p>]]></content>
    <author>
      <name>Vadim Belman</name>
    </author>
    <category term="Raku"/>
    <category term="JSON"/>
    <category term="serialization"/>
    <category term="module"/>
    <summary type="html"><![CDATA[This will be a short one. I have recently released a family of WWW::GCloud modules for accessing Google Cloud services. Their REST API is, apparently, JSON-based. So, I made use of the existing JSON::Class. Unfortunately, it was missing some features critically needed for my work project. I implemented a couple of workarounds, but still felt like it’s not the way it has to be. Something akin to LibXML::Class would be great to have… There was a big “but” in this. We already have XML::Class, LibXML::Class, and the current JSON::Class. All are responsible for doing basically the same thing: de-/serializing classes. If I wanted another JSON serializer then I had to take into account that JSON::Class is already taken. There are three ways to deal with it: Branch the current JSON::Class and re-implement it as a backward-incompatible version. Give the new module a different name. Implement own version and publish it under my name. The first two options didn’t appeal to me. The third one is now about to happen. I expect it to be a stress-test for Raku ecosystem as, up to my knowledge, it’s going to be the first case where two different modules share the same name but not publishers. As a little reminder: To use the old module one would have to have JSON::Class:auth&lt;zef:jonathanstowe&gt; in their dependencies and, perhaps, in their use statement. The new module will be available as JSON::Class:auth&lt;zef:vrurg&gt;. There is still some time before I publish it because the documentation is not ready yet. Let’s 🤞🏻.]]></summary>
  </entry>
  <entry>
    <title>Sorting numbers in Raku with the help of ChatGPT</title>
    <link rel="alternate" href="https://andrewshitov.com/2023/09/05/sorting-numbers-in-raku-with-the-help-of-chatgpt/" type="text/html"/>
    <content type="html">
&lt;p&gt;In this post I will show you the solution to the &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-233/#TASK2"&gt;Task 2 of this week’s Weekly Challenge 233&lt;/a&gt;. This time I was using the help of ChatGPT, which offered a very nice solution.&lt;/p&gt;



&lt;div class="wp-block-group"&gt;&lt;div class="wp-block-group__inner-container"&gt;
&lt;h2 id="TASK2"&gt;Task 2: Frequency Sort&lt;/h2&gt;



&lt;p&gt;You are given an array of integers.&lt;/p&gt;



&lt;p&gt;Write a script to sort the given array in increasing order based on the frequency of the values. If multiple values have the same frequency then sort them in decreasing order.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @ints = (1,1,2,2,2,3)
Ouput: (3,1,1,2,2,2)

'3' has a frequency of 1
'1' has a frequency of 2
'2' has a frequency of 3
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @ints = (2,3,1,3,2)
Ouput: (1,3,3,2,2)

'2' and '3' both have a frequency of 2, so they are sorted in decreasing order.
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @ints = (-1,1,-6,4,5,-6,1,4,1)
Ouput: (5,-1,4,4,-6,-6,1,1,1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;



&lt;p&gt;I asked ChatGPT the following: ‘Create a program. Here is the description of the task.’ To make sure the result is in the Raku programming language, I also added the following instruction in my local settings so that it knows which programming language I prefer by default.&lt;/p&gt;



&lt;div class="wp-block-image"&gt;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img src="https://andrewshitov.com/wp-content/uploads/2023/09/Screenshot-2023-09-05-at-15.49.04-1024x648.png" alt="" class="wp-image-7031" width="484" height="305" srcset="https://andrewshitov.com/wp-content/uploads/2023/09/Screenshot-2023-09-05-at-15.49.04-1024x648.png 1024w, https://andrewshitov.com/wp-content/uploads/2023/09/Screenshot-2023-09-05-at-15.49.04-300x190.png 300w, https://andrewshitov.com/wp-content/uploads/2023/09/Screenshot-2023-09-05-at-15.49.04-768x486.png 768w, https://andrewshitov.com/wp-content/uploads/2023/09/Screenshot-2023-09-05-at-15.49.04.png 1112w" sizes="(max-width: 484px) 85vw, 484px" /&gt;&lt;/figure&gt;&lt;/div&gt;



&lt;p&gt;The solution generated by ChatGPT was quite good with a small mistake.&lt;/p&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;ChatGPT:&lt;/strong&gt; Sure, here&amp;#8217;s a Raku program that implements the described sorting algorithm for the given task:&lt;/em&gt;&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;sub frequency-sort(@arr) {
    my %freq;

    %freq{$_}++ for @arr;
    my @sorted = @arr.sort: {
        %freq{$^b} &amp;lt;=&gt; %freq{$^a} ||
        $^b &amp;lt;=&gt; $^a
    };

    return @sorted;
}

my @ints = (1, 1, 2, 2, 2, 3);
my @sorted = frequency-sort(@ints);

say "Input:  @ints";
say "Output: @sorted";&lt;/pre&gt;



&lt;p&gt;First, Raku would not interpolate arrays, so &lt;code&gt;say "Input: @ints"&lt;/code&gt; prints the string literary: &lt;code&gt;Input: @ints&lt;/code&gt;. Second, in the sorting rule, sorting by frequency must be ascending rather than descending, so we need to switch the placeholder variables &lt;code&gt;$^b&lt;/code&gt; and &lt;code&gt;$^a&lt;/code&gt;. &lt;/p&gt;



&lt;p&gt;In the rest, ChatGPT did a good work. It computed the frequency using a loop, and I especially liked how it addressed the requirement to sort by two dimensions.&lt;/p&gt;



&lt;p&gt;Here is the full program with the above-mentioned corrections:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;sub frequency-sort(@arr) {
    my %freq;
    %freq{$_}++ for @arr;

    my @sorted = @arr.sort: {
        &lt;strong&gt;%freq{$^a} &amp;lt;=&gt; %freq{$^b} ||
&lt;/strong&gt;        &lt;strong&gt;$^b &amp;lt;=&gt; $^a&lt;/strong&gt;
    };

    return @sorted;
}

my @tests =
    (1, 1, 2, 2, 2, 3),
    (2, 3, 1, 3, 2),
    (-1, 1, -6, 4, 5, -6, 1, 4, 1);

say frequency-sort($_) for @tests;&lt;/pre&gt;



&lt;p&gt;This program prints the following output for the given test cases:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;$ raku ch-2.raku
[3 1 1 2 2 2]
[1 3 3 2 2]
[5 -1 4 4 -6 -6 1 1 1]&lt;/pre&gt;



&lt;ul&gt;&lt;li&gt;&lt;em&gt;&lt;a href="https://github.com/ash/perlweeklychallenge-club/tree/master/challenge-233/ash/raku"&gt;Code on GitHub&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;&lt;li&gt;&lt;em&gt;&lt;a href="https://andrewshitov.com/raku-challenges-index/"&gt;Navigation to the&amp;nbsp;Raku challenges&amp;nbsp;post series&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Solving the task from The Weekly Challenge 233, where you need to sort numbers by two dimensions.</div>
    </summary>
    <author>
      <name>Andrew Shitov</name>
    </author>
    <id>https://andrewshitov.com/?p=7030</id>
    <published>2023-09-05T13:58:16Z</published>
    <updated>2023-09-05T13:58:16Z</updated>
    <category term="ChatGPT"/>
    <category term="Raku"/>
    <category term="Raku challenges"/>
  </entry>
  <entry>
    <title>Working with words in the Raku programming language</title>
    <link rel="alternate" href="https://andrewshitov.com/2023/09/04/working-with-words-in-the-raku-programming-language/" type="text/html"/>
    <content type="html">
&lt;p&gt;In this post, I will demonstrate my solution to another &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-233/#TASK1"&gt;Task of The Weekly Challenge, week 233&lt;/a&gt;. Here’s how it reads:&lt;/p&gt;



&lt;div class="wp-block-group"&gt;&lt;div class="wp-block-group__inner-container"&gt;
&lt;h2&gt;Similar words&lt;/h2&gt;



&lt;p&gt;You are given an array of words made up of alphabets only.&lt;/p&gt;



&lt;p&gt;Write a script to find the number of pairs of similar words. Two words are similar if they consist of the same characters.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @words = ("aba", "aabb", "abcd", "bac", "aabc")
Output: 2

Pair 1: similar words ("aba", "aabb")
Pair 2: similar words ("bac", "aabc")
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @words = ("aabb", "ab", "ba")
Output: 3

Pair 1: similar words ("aabb", "ab")
Pair 2: similar words ("aabb", "ba")
Pair 3: similar words ("ab", "ba")
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @words = ("nba", "cba", "dba")
Output: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;



&lt;p&gt;There’s a slight moment that may be needs extra comments. In the second example all three words constructed of the same two letters, &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt;. So, all of the three words match the definition of a ‘similar’ word. But as the task needs to find pairs, we need to construct all the possible pairs out of those three words.&lt;/p&gt;



&lt;p&gt;In my solution, I chose to use a handy &lt;code&gt;classify&lt;/code&gt; method. For an array, it creates a hash, where the keys are the common classifying symbol, and the values are the lists of the input elements that match this classification property.&lt;/p&gt;



&lt;p&gt;Here is the whole first program together with all the test cases provided in the description. The program maps every word to a corresponding string that consists of the sorted unique letters in the word.&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;my @tests = ["aba", "aabb", "abcd", "bac", "aabc"],
            ["aabb", "ab", "ba"],
            ["nba", "cba", "dba"];

for @tests -&amp;gt; @words {
    say &lt;strong&gt;@words.classify(*.comb.unique.sort.join)&lt;/strong&gt;.grep(*.value.elems &amp;gt; 1);
}&lt;/pre&gt;



&lt;p&gt;For example, the word &lt;em&gt;aba&lt;/em&gt; will be associated with the key &lt;em&gt;ab&lt;/em&gt;. The program prints the following output:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;$ raku ch-1.raku 
(ab =&amp;gt; [aba aabb] abc =&amp;gt; [bac aabc])
(ab =&amp;gt; [aabb ab ba])
()&lt;/pre&gt;



&lt;p&gt;The format of the output differs from the examples, but it can be enhanced if needed. My goal was to create a compact solution &lt;img src="https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /&gt;&lt;/p&gt;



&lt;p&gt;But I would assume that you’d be interested in looking at what &lt;code&gt;classify&lt;/code&gt; produces. I am also curious. For the same &lt;code&gt;@tests&lt;/code&gt;, it returns the following three hashes:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;{ab =&amp;gt; [aba aabb], abc =&amp;gt; [bac aabc], abcd =&amp;gt; [abcd]}
{ab =&amp;gt; [aabb ab ba]}
{abc =&amp;gt; [cba], abd =&amp;gt; [dba], abn =&amp;gt; [nba]}&lt;/pre&gt;



&lt;p&gt;As you see, each string was put into one of the classification bins.&lt;/p&gt;



&lt;p&gt;The second part of the task is to find &lt;em&gt;pairs&lt;/em&gt;. After the &lt;code&gt;grep&lt;/code&gt;, we already filtered out everything that has less than two elements, so if data passed through this filter, there will be at least one pair. For bigger arrays, we can use another Raku’s built-in mechanism: the &lt;code&gt;combinations&lt;/code&gt; method.&lt;/p&gt;



&lt;p&gt;The updated mail loop of the program looks like this now.&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;for @tests -&gt; @words {
    say "Test case: ", @words;

    my %classification = @words.classify(*.comb.unique.sort.join).grep(*.value.elems &gt; 1);

    my $pairs = 0;
    for %classification.kv -&gt; $k, $v {
        &lt;strong&gt;my @pairs = $v.combinations(2);&lt;/strong&gt;
        &lt;strong&gt;$pairs += @pairs.elems;&lt;/strong&gt;

        say "$k: ", @pairs;
    }
    say "Answer: $pairs pair{$pairs == 1 ?? '' !! 's'}.\n";
}&lt;/pre&gt;



&lt;p&gt;The ‘redundant’ code here is added just to have a more detailed output so that we can see which pairs were actually found. Let us look at the output for the initial test cases:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;$ raku ch-1.raku
Test case: [aba aabb abcd bac aabc]
ab: [(aba aabb)]
abc: [(bac aabc)]
Answer: 2 pairs.

Test case: [aabb ab ba]
ab: [(aabb ab) (aabb ba) (ab ba)]
Answer: 3 pairs.

Test case: [nba cba dba]
Answer: 0 pairs.&lt;/pre&gt;



&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/ash/perlweeklychallenge-club/tree/master/challenge-233/ash/raku"&gt;Code on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://andrewshitov.com/raku-challenges-index/"&gt;Navigation to the&amp;nbsp;&lt;em&gt;Raku challenges&lt;/em&gt;&amp;nbsp;post series&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">A solution to the task 1 of the Weekly Challenge 233, where the goal is to find the words constructed from the same letters.</div>
    </summary>
    <author>
      <name>Andrew Shitov</name>
    </author>
    <id>https://andrewshitov.com/?p=7020</id>
    <published>2023-09-04T19:46:41Z</published>
    <updated>2023-09-04T19:46:41Z</updated>
    <category term="Raku"/>
    <category term="Raku challenges"/>
  </entry>
  <entry>
    <title>A couple of tasks solved in Raku</title>
    <link rel="alternate" href="https://andrewshitov.com/2023/08/21/a-couple-of-tasks-solved-in-raku/" type="text/html"/>
    <content type="html">
&lt;p&gt;On this page, I’ll briefly cover the solutions to the tasks for this week’s &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-231/"&gt;Weekly Challenge #231&lt;/a&gt;.&lt;/p&gt;



&lt;a name="task1"&gt;&lt;/a&gt;&lt;h2&gt;Task 1&lt;/h2&gt;



&lt;div class="wp-block-group"&gt;&lt;div class="wp-block-group__inner-container"&gt;
&lt;p&gt;You are given an array of distinct integers.&lt;/p&gt;



&lt;p&gt;Write a script to find all elements that is neither minimum nor maximum. Return -1 if you can’t.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @ints = (3, 2, 1, 4)
Output: (3, 2)

The minimum is 1 and maximum is 4 in the given array. So (3, 2) is neither min nor max.
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @ints = (3, 1)
Output: -1
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @ints = (2, 1, 3)
Output: (2)

The minimum is 1 and maximum is 3 in the given array. So 2 is neither min nor max.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;



&lt;p&gt;Here is my original solution in the Raku programming language.&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;sub solve(@data) {
    @data.grep: * != (@data.min, @data.max).any
}&lt;/pre&gt;



&lt;p&gt;As the tasks requires that we print &lt;code&gt;-1&lt;/code&gt; when there are no elements in the output, let us add an update to satisfy this requirement:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;sub solve(@data) {
    &lt;strong&gt;(&lt;/strong&gt;@data.grep: * != (@data.min, @data.max).any&lt;strong&gt;) || -1&lt;/strong&gt;
}&lt;/pre&gt;



&lt;p&gt;The &lt;code&gt;*&lt;/code&gt; in this code will actually replace the &lt;code&gt;$_&lt;/code&gt; variable. Would you prefer it, you may use &lt;code&gt;$_&lt;/code&gt;, but you’ll need parentheses in this case. So, instead of &lt;code&gt;@data.grep: * != ...&lt;/code&gt;, you need &lt;code&gt;@data.grep({$_ != ...})&lt;/code&gt;, which may be a less clear code for some people.&lt;/p&gt;



&lt;p&gt;Finally, let us use some math notation and replace calling the &lt;code&gt;.any&lt;/code&gt; method with a ‘contains’ operator:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;sub solve(@data) {
    (@data.grep: * &lt;strong&gt;∉&lt;/strong&gt; (@data.min, @data.max)) || -1
}&lt;/pre&gt;



&lt;p&gt;Well, actually, ‘does not contain’. And this is my final solution. &lt;/p&gt;



&lt;p&gt;Note that you may want to use the &lt;code&gt;.minmax&lt;/code&gt; method instead of two calls to &lt;code&gt;.min&lt;/code&gt; and &lt;code&gt;.max&lt;/code&gt;, but &lt;code&gt;.minmax&lt;/code&gt; returns a range, which is not that suitable for this task.&lt;/p&gt;



&lt;p&gt;Adding some test cases and passing them to the &lt;code&gt;solve&lt;/code&gt; function:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;my @tests = (3, 2, 1, 4), (3, 1), (2, 1, 3);
say solve($_) for @tests;&lt;/pre&gt;



&lt;p&gt;The program prints the expected output:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;$ raku ch-1.raku 
(3 2)
-1
(2)&lt;/pre&gt;



 &lt;a name="task2"&gt;&lt;/a&gt;&lt;h2&gt;Task 2&lt;/h2&gt;



&lt;div class="wp-block-group"&gt;&lt;div class="wp-block-group__inner-container"&gt;
&lt;p&gt;You are given a list of passenger details in the form “9999999999A1122”, where 9 denotes the phone number, A the sex, 1 the age and 2 the seat number.&lt;/p&gt;



&lt;p&gt;Write a script to return the count of all senior citizens (age &amp;gt;= 60).&lt;/p&gt;



&lt;h4 id="example-1-1"&gt;Example 1&lt;/h4&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @list = ("7868190130M7522","5303914400F9211","9273338290F4010")
Ouput: 2

The age of the passengers in the given list are 75, 92 and 40.
So we have only 2 senior citizens.
&lt;/code&gt;&lt;/pre&gt;



&lt;h4 id="example-2-1"&gt;Example 2&lt;/h4&gt;



&lt;pre class="wp-block-code"&gt;&lt;code&gt;Input: @list = ("1313579440F2036","2921522980M5644")
Ouput: 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;



&lt;p&gt;Apparently, the solution requires extracting information from a string in a specific format. It is not quite clear from the description whether the strings always contains the same number of characters, and thus the age and seat number are always two-digit values. But let’s use this assumption.&lt;/p&gt;



&lt;p&gt;As we do not need any other information from the ticket code, no need to properly parse it, so I preferred anchoring around the only letter in the string and consider the next two digits as the age. Of course, you may make it simpler and just extract the two digits counting from the end of the string.&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;sub is-sinior($ticket) {
    ~($ticket ~~ / &lt;strong&gt;&amp;lt;alpha&amp;gt; (\d\d)&lt;/strong&gt; /)[0] &amp;gt;= 75
}&lt;/pre&gt;



&lt;p&gt;Unlike Perl 5, Raku ignores spaces in regexes by default, so I added some air to it. On the other hand, extracting matches may seem a bit more complicated.&lt;/p&gt;



&lt;p&gt;For the first given example (see task’s description), the Match object contains the following information:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;｢M75｣
  alpha =&amp;gt; ｢M｣
  0 =&amp;gt; ｢75｣&lt;/pre&gt;



&lt;p&gt;So, I am taking the 0&lt;sup&gt;th&lt;/sup&gt; element using &lt;code&gt;[0]&lt;/code&gt; and stringily it with the &lt;code&gt;~&lt;/code&gt; prefix operator.&lt;/p&gt;



&lt;p&gt;In essence, the task has been solved. Let’s add the test cases and run them:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;my @tests = ('7868190130M7522', '5303914400F9211', '9273338290F4010'),
            ('1313579440F2036', '2921522980M5644');

for @tests -&amp;gt; @tickets {
    say +@tickets.grep({is-sinior($_)});
}&lt;/pre&gt;



&lt;p&gt;The program prints:&lt;/p&gt;



&lt;pre class="wp-block-preformatted"&gt;$ raku ch-2.raku 
2
0&lt;/pre&gt;



&lt;p&gt;&lt;/p&gt;



&lt;p class="has-text-align-center"&gt;*  * *&lt;/p&gt;



&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/ash/perlweeklychallenge-club/tree/master/challenge-231/ash/raku"&gt;Code on GitHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://andrewshitov.com/raku-challenges-index/"&gt;Navigation to the&amp;nbsp;&lt;em&gt;Raku challenges&lt;/em&gt;&amp;nbsp;post series&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Two tasks from the Weekly Challenge 231 solved in the Raku programming language.</div>
    </summary>
    <author>
      <name>Andrew Shitov</name>
    </author>
    <id>https://andrewshitov.com/?p=7010</id>
    <published>2023-08-21T11:31:17Z</published>
    <updated>2023-08-21T11:31:17Z</updated>
    <category term="Raku"/>
    <category term="Raku challenges"/>
  </entry>
  <entry>
    <title type="html">Easy-peasy Service From A Role</title>
    <link href="https://vrurg.github.io/2023/07/19/easy-peasy-service-from-a-role" rel="alternate" type="text/html" title="Easy-peasy Service From A Role"/>
    <published>2023-07-19T00:00:00-04:00</published>
    <updated>2023-07-19T00:00:00-04:00</updated>
    <id>https://vrurg.github.io/2023/07/19/easy-peasy-service-from-a-role</id>
    <content type="html" xml:base="https://vrurg.github.io/2023/07/19/easy-peasy-service-from-a-role"><![CDATA[<p>I was always concerned about making things easier.</p>

<p>No, not this way. A technology must be easy to start with, but also be easy in accessing its advanced or fine-tunable
features. Let’s have an example of the former.</p>

<!--more-->

<h2 id="disclaimer">Disclaimer</h2>

<p>This post is a quick hack, no proof-reading or error checking is done. Please, feel free to report any issue.</p>

<h1 id="the-task">The Task</h1>

<p>Part of my ongoing project is to deal with JSON data and deserialize it into Raku classes. This is certainly a task
for <a href="https://raku.land/zef:jonathanstowe/JSON::Class"><code class="language-plaintext highlighter-rouge">JSON::Class</code></a>. So far, so good.</p>

<p>The keys of JSON structures tend to use lower camel case which is OK, but we like
<a href="https://en.wikipedia.org/wiki/Naming_convention_(programming)">kebabing</a> in Raku. Why not, there is
<a href="https://raku.land/zef:jonathanstowe/JSON::Name"><code class="language-plaintext highlighter-rouge">JSON::Name</code></a>. But using it:</p>

<ul>
  <li>Will hide the original names. This would break the principle of easy start because one would rather expect to see them as attributes of an object. Having both the original naming and kebabed would be more desirable.</li>
  <li>Would require a lot of manual work on my side.</li>
</ul>

<h1 id="the-assets">The Assets</h1>

<p>There are roles. At the point I came to the final solution I was already doing something like<sup id="fnref:fictional-naming" role="doc-noteref"><a href="#fn:fictional-naming" class="footnote" rel="footnote">1</a></sup>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class SomeStructure does JSONRecord {...}
</code></pre></div></div>

<p>Then there is <a href="https://raku.land/zef:vrurg/AttrX::Mooish"><code class="language-plaintext highlighter-rouge">AttrX::Mooish</code></a>, which is my lifevest on many occasions:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>use AttrX::Mooish;
class Foo {
    has $.foo is mooish(:alias&lt;bar&gt;);
}
my $obj = Foo.new: bar =&gt; "the answer";
say $obj.foo; # the answer
</code></pre></div></div>

<p>Apparently, this way it would still be a lot of manual interaction with aliasing, and that’s what I was already doing
for a while until realized that there is a bettter way. But be back to this later…</p>

<p>And, eventually, there are traits and MOP.</p>

<h1 id="the-solution">The Solution</h1>

<h2 id="name-translation">Name Translation</h2>

<p>That’s the easiest part. What I want is to <code class="language-plaintext highlighter-rouge">makeThisName</code> look like <code class="language-plaintext highlighter-rouge">make-this-name</code>. Ha, big deal!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unit module JSONRecord::Utils;

our sub kebabify-attr(Attribute:D $attr) {
    if $attr.name ~~ /&lt;.lower&gt;&lt;.upper&gt;/ {
        my $alias = (S:g/&lt;lower&gt;&lt;upper&gt;/$&lt;lower&gt;-$&lt;upper&gt;/).lc given $attr.name.substr(2);
        ...
    }
}
</code></pre></div></div>

<p>I don’t export the sub because it’s for internal use mostly. Would somebody need it for other purposes it’s a rare case where a long name like <code class="language-plaintext highlighter-rouge">JSONRecord::Utils::kebabify-attr($attr)</code> must not be an issue.</p>

<p><em>The sub is not optimal, it’s what I came up with while expermineting with the approach. The number of method calls and regexes can be reduced.</em></p>

<p>I’ll get back later to the yada-yada-yada up there.</p>

<h2 id="automate-attribute-processing">Automate Attribute Processing</h2>

<p>Now we need a bit of MOP magic. To handle all attributes of a class we need to iterate over them and apply the aliasing. The first what comes to mind is to use role body because it is invoked at the early class composition times:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unit role JSONRecord;

for ::?CLASS.^attributes(:local) -&gt; $attr {
    # take care of it...
}
</code></pre></div></div>

<p>Note the word “early” I used above. It actually means that when role’s body is executed there are likely more roles waiting for their turn to be composed into the class. So, there are likely more attributes to be added to the class.</p>

<p>But we can override <code class="language-plaintext highlighter-rouge">Metamodel::ClassHOW</code> <code class="language-plaintext highlighter-rouge">compose_attributes</code> method of our target <code class="language-plaintext highlighter-rouge">::?CLASS</code> and rest assured no one would be missed:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unit role JSONRecordHOW;
use JSONRecord::Utils;

method compose_attributes(Mu \obj, |) {
    for self.attributes(obj, :local) -&gt; $attr {
        # Skip if it already has `is mooish` trait applied – we don't want to mess up with user's intentions.
        next if $attr ~~ AttrX::Mooish::Attribute;
        JSONRecord::Utils::kebabify-attr($attr);
    }
    nextsame
}
</code></pre></div></div>

<h2 id="the-role-does-it-all">The Role Does It All</h2>

<p>Basically, that’s all we currently need to finalize the solution. We can still use role’s body to implement the key elements of it:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unit role JSONRecord;
use JSONRecordHOW;

unless ::?CLASS.HOW ~~ JSONRecordHOW {
    ::?CLASS.HOW does JSONRecordHOW;
}
</code></pre></div></div>

<p>Job done! <em>Don’t worry, I haven’t forgot about the yada-yada-yada above!</em></p>

<p>But…</p>

<p>The original record role name itself is even longer than <code class="language-plaintext highlighter-rouge">JSONRecord</code>, and it consists of three parts. I’m lazy. There are a lot of JSON structures and I want less typing per each. A trait? <code class="language-plaintext highlighter-rouge">is jrecord</code>?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unit role JSONRecord;

multi sub trait_mod:&lt;is&gt;(Mu:U \type, Bool:D :$jrecord) is export {
    unless type.HOW ~~ JSONRecordHOW {
        type.HOW does JSONRecordHOW
        type.^add_role(::?ROLE);
    }
}
</code></pre></div></div>

<p>Now, instead of <code class="language-plaintext highlighter-rouge">class SomeRecord does JSONRecord</code> I can use <code class="language-plaintext highlighter-rouge">class SomeRecord is jrecord</code>. In the original case the win is even bigger.</p>

<h2 id="the-yada">The Yada???</h2>

<p>There is absolutely nothing funny about it. Just a common way to keep a reader interested!</p>

<p>Seriously.</p>

<p>The reason for the yada in that snippet is to avoid a distraction from the primary purpose of the example. Here is what is going on there:</p>

<p>I want <code class="language-plaintext highlighter-rouge">AttrX::Mooish</code> to do the dirty work for me. Eventually, what is needed is to apply the <code class="language-plaintext highlighter-rouge">is mooish</code> trait as shown above. But the traits are just subs. Therefore all is needed now is to:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&amp;trait_mod:&lt;is&gt;($attr, :mooish(:$alias));
</code></pre></div></div>

<p>Because this is what Raku does internally when encounters <code class="language-plaintext highlighter-rouge">is mooish(:alias(...))</code>. The final version of the kebabifying sub is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>our sub kebabify-attr(Attribute:D $attr) {
    if $attr.name ~~ /&lt;.lower&gt;&lt;.upper&gt;/ {
        my $alias = (S:g/&lt;lower&gt;&lt;upper&gt;/$&lt;lower&gt;-$&lt;upper&gt;/).lc given $attr.name.substr(2);
        &amp;trait_mod:&lt;is&gt;($attr, :mooish(:$alias));
    }
}
</code></pre></div></div>

<p>Since the sub is used by the HOW above, we can say that the <code class="language-plaintext highlighter-rouge">&amp;trait_mod&lt;is&gt;</code> would be called at compile time<sup id="fnref:not-always" role="doc-noteref"><a href="#fn:not-always" class="footnote" rel="footnote">2</a></sup>.</p>

<h2 id="the-use">The Use</h2>

<p>Now, it used to be:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class SomeRecord does JSONRecord {
    has $.aLongAttrName is mooish(:alias&lt;a-long-attr-name&gt;);
    has $.shortname;
}
</code></pre></div></div>

<p>Where, as you can see, I had to transfer JSON key names to attribute names, decide where aliasing is needed, add it, and make sure no mistakes were made or attributes are missed.</p>

<p>With the above rather simple tweaks:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class SomeRecord is jrecord {
    has $.aLongAttrName;
    has $.shortname;
}
</code></pre></div></div>

<p>Job done.</p>

<h2 id="the-stupidy">The Stupidy</h2>

<p>Before I came down to this solution I’ve got 34 record classes implemented using the old approach. Some are little, some are quite big. But it most certainly could’ve taken much less time would I have the trait at my disposal back then…</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:fictional-naming" role="doc-endnote">
      <p>Naming is totally fictional. <a href="#fnref:fictional-naming" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:not-always" role="doc-endnote">
      <p>Most likely, but there are exceptions. It barely changes a lot, but certainly falls out of the scope of this post. <a href="#fnref:not-always" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content>
    <author>
      <name>Vadim Belman</name>
    </author>
    <category term="Raku"/>
    <category term="trait"/>
    <category term="roles"/>
    <category term="did-you-know"/>
    <summary type="html"><![CDATA[I was always concerned about making things easier. No, not this way. A technology must be easy to start with, but also be easy in accessing its advanced or fine-tunable features. Let’s have an example of the former.]]></summary>
  </entry>
  <entry>
    <title type="html">Another Article Before A Break</title>
    <link href="https://vrurg.github.io/2023/07/05/another-article-before-a-pause" rel="alternate" type="text/html" title="Another Article Before A Break"/>
    <published>2023-07-05T00:00:00-04:00</published>
    <updated>2023-07-05T00:00:00-04:00</updated>
    <id>https://vrurg.github.io/2023/07/05/another-article-before-a-pause</id>
    <content type="html" xml:base="https://vrurg.github.io/2023/07/05/another-article-before-a-pause"><![CDATA[<p>I have managed to finish one more article in the <a href="/arfb.html">Advanced Raku For Beginners</a> series, this time about <a href="/arfb-publication/09-type-and-object-composition/">type
and object composition in Raku</a>.</p>

<!--more-->

<p>It’s likely to take a long before I can write another.</p>]]></content>
    <author>
      <name>Vadim Belman</name>
    </author>
    <category term="Raku"/>
    <category term="ARFB"/>
    <category term="article"/>
    <category term="publication"/>
    <summary type="html"><![CDATA[I have managed to finish one more article in the Advanced Raku For Beginners series, this time about type and object composition in Raku.]]></summary>
  </entry>
  <entry>
    <title type="html">Did you know that…</title>
    <link href="https://vrurg.github.io/2023/07/04/did-you-know-that" rel="alternate" type="text/html" title="Did you know that…"/>
    <published>2023-07-04T17:24:07-04:00</published>
    <updated>2023-07-04T17:24:07-04:00</updated>
    <id>https://vrurg.github.io/2023/07/04/did-you-know-that</id>
    <content type="html" xml:base="https://vrurg.github.io/2023/07/04/did-you-know-that"><![CDATA[<p>Once, long ago, coincidentally a few people were asking the same question: <em>how do I get a method object of a class?</em></p>

<!--more-->

<p>Answers to the question would depend on particular circumstances of the code where this functionality is needed. One
would be about using MOP methods like <code class="language-plaintext highlighter-rouge">.^lookup</code>, the other is to use method name and indirect resolution on invocant:
<code class="language-plaintext highlighter-rouge">self."$method-name"(...)</code>. Both are the most useful, in my view. But sometimes declaring a method as <code class="language-plaintext highlighter-rouge">our</code> can be
helpful too:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Foo {
    our method bar {}
}
say Foo::&lt;&amp;bar&gt;.raku;
</code></pre></div></div>

<p>Just don’t forget that this way we always get the method of class <code class="language-plaintext highlighter-rouge">Foo</code>, even if a subclass overrides method <code class="language-plaintext highlighter-rouge">bar</code>.</p>]]></content>
    <author>
      <name>Vadim Belman</name>
    </author>
    <category term="did-you-know"/>
    <category term="fact"/>
    <category term="Raku"/>
    <summary type="html"><![CDATA[Once, long ago, coincidentally a few people were asking the same question: how do I get a method object of a class?]]></summary>
  </entry>
  <entry>
    <title>Recollections from the Raku Core Summit</title>
    <link rel="alternate" href="https://6guts.wordpress.com/2023/06/18/recollections-from-the-raku-core-summit/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>The first Raku Core Summit, a gathering of folks who work on “core” Raku things, was held on the first weekend of June, and I was one of those invited to attend. It’s certainly the case that I’ve been a lot less active in Raku things over the last 18 months, and I hesitated for a moment over whether to go. However, even if I’m not so involved day to day in Raku things at the moment, I’m still keen to see the language and its ecosystem move forward, and – having implemented no small amount of the compiler and runtime since getting involved in 2007 – I figured I’d find something useful to do there!</p>



<p>The area I was especially keen to help with is RakuAST, something I started, and that I’m glad I managed to bring far enough that others could see the potential and were excited enough to pick it up and run with it.</p>



<p>One tricky aspect of implementing Raku is the whole notion of BEGIN time (of course, this is also one of the things that makes Raku powerful and thus is widely used). In short, BEGIN time is about running code during the compile time, and in Raku there’s no separate meta-language; anything you can do at runtime, you can (in principle) do at compile time too. The problem at hand was what to do about references from code running at compile time to lexically scoped symbols in the surrounding scope. Of note, that lexical scope is still being compiled, so doesn’t really exist yet so far as the runtime is concerned. The current compiler deals with this by building up an entire flattened table of everything that is visible, and installing it as a fake outer scope while running the BEGIN-time code. This is rather costly, and the hope in RakuAST was to avoid this kind of approach in general.</p>



<p>A better solution seemed to be at hand by spotting such references during compilation, resolving them, and fixating them – that is, they get compiled as if they were lookups into a constant table. (This copies the suggested approach for quasiquoted code that references symbols in the lexical scope of where the quasiquoted code appears.) This seemed promising, but there’s a problem:</p>



<pre class="wp-block-code"><code>my $x = BEGIN %*ENV&lt;DEBUG&gt; ?? -&gt; $x { note "Got $x"; foo($x) } !! -&gt; $x { foo($x) };</code></pre>



<p>It’s fine to post-declare subs, and so there’s no value to fixate. Thankfully, the generalized dispatch mechanism can ride to the rescue; we can:</p>



<ol class="wp-block-list">
<li>Create a placeholder object with an attribute to hold the resolution</li>



<li>Compile the lookup into a use of a dispatcher that reads this attribute and indicates that this is a constant result of the dispatch (so it is stored in the inline cache, and after specialization will be just as cheap as any other sub call). If the attribute is not set, that means we tried to run the code before declaring the sub, and the object can carry a bit of extra metadata in order to give a good error message.</li>



<li>Keep track of this object in the compiler, and – upon declaration of the sub – install it into the placeholder object.</li>



<li>Give an error if we reach the end of the compilation unit with an unfilled placeholder.</li>
</ol>



<p>When compiling Raku code, timing is everything. I knew this and tried to account for it in the RakuAST design from the start, but a couple of things in particular turned out a bit awkward.</p>



<ul class="wp-block-list">
<li>Every node wanting to do something at BEGIN time would implement RakuAST::BeginTime, and in doing so would have its method to perform a BEGIN-time action called at the appropriate point. So far so good, for most program elements. However, it turns out that some larger program elements want to do things at compile time both at the point they start <em>and</em> at the point they end. I’d added a “I want my BEGIN time before my children” mechanism, but that didn’t help program elements that wanted action at both points. Thus, I started a branch that introduces parse time. For “leaf” elements that is the same as BEGIN time, but for things like packages and routines, which have a bunch of stuff on the inside, it happens before we go parsing their inner scope.</li>



<li>The RakuAST tree is an object graph where every node knows its children, but nodes do not reference their parents. However, some program elements need to find out about their enclosing context, for example a method wants to know about the class it is being declared in. Thus I came up with a notion of attach targets (things that child nodes want to discover) and attaching nodes (the children that want to “attach” to a parent – I’m not sure I got the naming right here, in hindsight). I guess with my IDE work it also appealed that one might be able to introspect these kinds of relationships for tooling purposes – although in reality the attaching work was highly imperative anyway. But with parse and begin time clarified, it also seemed that attachment work could happen in either (or do different work in both), but also it was hazy exactly when attachment happened, and it could end up happening multiple times, which was fragile. Thus, while the notion of attachment targets should survive – probably with a better name – the need for a RakuAST::Attaching went away. My branch also took on its elimination.</li>
</ul>



<p>I got a decent way into this restructuring work during the core summit, and hope to find time soon to get it a bit further along (I’ve been a mix of busy, tired, and had an eye infection to boot since getting back from the summit, so thus far there’s not been time for it).</p>



<p>I also took part in various other discussions and helped with some other things; those that are probably most worth mentioning are:</p>



<ul class="wp-block-list">
<li>There was quite a bit of talk about Raku Doc (formerly Pod6) and tidying up some aspects of its design and implementation. I’m pleased to see it is getting a rather cleaner implementation in the RakuAST-based compiler frontend. (Story illustrating why: when developing the Comma IDE I built a small and very specialized Raku grammar to Java lexer/parser compiler, in order to nail the Raku language’s syntactic structure, and I followed what Rakudo’s grammar did relatively closely in all but two places: operator parsing – because it just needed to be different for the IntelliJ platform’s tree builder engine – and Pod6, because it was easier to read the spec and implement it afresh than it was to decipher Rakudo’s implementation of it!)</li>



<li>There was a long-standing problem that looked like the regex engine massively leaked memory in certain cases, but nobody could pin down the leak. The reason was that it wasn’t actually leaking, it was just creating sufficient backtracking state to go quadratic in the size of the input string. MoarVM only stores an array header in the nursery (the region of memory it allocates in, and whose fullness is the trigger for doing a GC run); the array body is allocated using a standard allocator. There are good things about this, but a less good thing is that if you allocate loads of large arrays in quick succession, you’ll allocate lots of memory, but not eat much of the nursery, and so it won’t be cleaned up very soon. The regex in question was doing exactly that: since it captured into an inner cursor, and cursors are in principle immutable, then it ended up cloning the array at every backtracking step, and doing so in a fairly tight loop. Closer examination revealed that the cloning of the backtrack stack was, however, overly defensive; eliminating that copying led to a huge memory and time improvement. Still, it remains to make such large array allocations pressure the GC more (we already do a similar kind of thing for big integers).</li>



<li>I provided a few MoarVM hints that helped leont get support for asynchronous UNIX domain sockets implemented. Apparently that unblocks having an asynchronous Postgres driver, which would be most welcome for use in Cro applications, where the request handling is asynchronous but the database queries end up growing the thread pool by really blocking threads.</li>
</ul>



<p>Thanks goes to Liz for organizing the summit, to Wendy for keeping everyone so well fed and watered, to the rest of attendees for many interesting discussions over the three days, to TPRF and Rootprompt for sponsoring the event, and to Edument for supporting my attendance.</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">The first Raku Core Summit, a gathering of folks who work on “core” Raku things, was held on the first weekend of June, and I was one of those invited to attend. It’s certainly the case that I’ve been a … <a href="https://6guts.wordpress.com/2023/06/18/recollections-from-the-raku-core-summit/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>jnthnwrthngtn</name>
    </author>
    <id>http://6guts.wordpress.com/?p=603</id>
    <published>2023-06-18T15:58:04Z</published>
    <updated>2023-06-18T15:58:04Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-7864497598813874355.post-1747613800301306618</id>
    <published>2023-06-10T15:33:00.000-07:00</published>
    <updated>2023-06-10T15:33:02.737-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="raku"/>
    <title type="text">Retrospective of the MoarVM JIT</title>
    <content type="html">&lt;p style="text-align: left;"&gt;Hi hackers! Today the MoarVM JIT project is nearly 9 years old. I was inspired by Jonathan's &lt;a href="https://youtu.be/3lxuCr54ULE" target="_blank"&gt;presentation&lt;/a&gt; reflecting on the development of MoarVM, to do the same for the MoarVM JIT, for which I have been responsible.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-align: left;"&gt;For those who are unfamiliar, what is commonly understood as 'JIT compilation' for virtual machines is performed by two components in MoarVM.&lt;br /&gt;&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li style="text-align: left;"&gt;A framework for runtime type specialization ('&lt;a href="https://6guts.wordpress.com/2017/11/05/moarvm-specializer-improvements-part-3-optimizing-code/"&gt;spesh&lt;/a&gt;')&lt;/li&gt;&lt;li style="text-align: left;"&gt;A native code generation backend for the specialized code (the 'JIT').&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This post refers only to the native code generation backend component. It, too, is split into two mostly-independent systems:&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;A backend that emits code directly from MoarVM instructions from machine code templates (the 'lego' JIT compiler).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Another backend that transforms MoarVM instructions into an expression-based intermediate representation and compiles machine code based on that (the 'expression' compiler).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: left;"&gt;&lt;h4 style="text-align: left;"&gt;Things that worked well&lt;/h4&gt;&lt;ul style="text-align: left;"&gt;&lt;li style="text-align: left;"&gt;Using &lt;a href="https://luajit.org/dynasm.html" target="_blank"&gt;DynASM&lt;/a&gt; for code generation. Even though we had to extend it to &lt;a href="https://brrt-to-the-future.blogspot.com/2015/09/most-significant-bits.html"&gt;support register selection&lt;/a&gt;, using DynASM saved a lot of time compared to generating code 'from scratch'.&lt;br /&gt;&lt;/li&gt;&lt;li style="text-align: left;"&gt;Textual opcode templates for the expression compiler (mapping from MoarVM instructions to the JIT intermediate representation)&lt;/li&gt;&lt;li style="text-align: left;"&gt;&lt;a href="https://brrt-to-the-future.blogspot.com/2018/09/template-compiler-update.html" target="_blank"&gt;Type analysis&lt;/a&gt; for opcode templates (preventing bugs)&lt;br /&gt;&lt;/li&gt;&lt;li style="text-align: left;"&gt;Tiling for &lt;a href="https://brrt-to-the-future.blogspot.com/2015/07/tiles-and-compiler-compilers.html"&gt;instruction selection&lt;/a&gt;&lt;/li&gt;&lt;li style="text-align: left;"&gt;Using the &lt;a href="https://brrt-to-the-future.blogspot.com/2018/06/controlled-stack-hacking-for-moarvm-jit.html" target="_blank"&gt;on-stack return address&lt;/a&gt; as a current position marker (for the purpose of exception handling, lexical variable analysis etc.)&lt;/li&gt;&lt;/ul&gt;&lt;h4 style="text-align: left;"&gt;&amp;nbsp;Things that didn't work so well&amp;nbsp;&lt;/h4&gt;&lt;ul style="text-align: left;"&gt;&lt;li style="text-align: left;"&gt;Testing. MoarVM doesn't have a separate test suite but relies on the NQP and Rakudo tests. For the JIT compiler, this is essentially 'testing in production'. In hindsight, specific unit and integration tests would have been beneficial.&lt;/li&gt;&lt;li style="text-align: left;"&gt;Using an unordered intermediate representation for the 'expression' JIT. Against my expectation this &lt;a href="https://brrt-to-the-future.blogspot.com/2019/03/something-about-ir-optimization.html"&gt;prevented the implementation&lt;/a&gt; of common optimizations. And it made it nearly impossible to extend the 'expression' JIT to code segments longer than a basic block.&lt;br /&gt;&lt;/li&gt;&lt;li style="text-align: left;"&gt;Failing to deprecate the 'legacy' JIT compiler.&amp;nbsp;&lt;/li&gt;&lt;li style="text-align: left;"&gt;Despite some attempts I never truly succeeded in sharing the owernship of the JIT. &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style="text-align: left;"&gt;What's kind of ugly&lt;/h4&gt;&lt;ul style="text-align: left;"&gt;&lt;li style="text-align: left;"&gt;The 'expression' IR uses a completely different memory model (linear array with integer indexes) from the 'spesh' subsystem of which it is supposedly a part (which uses a more straightforward object graph coupled with arena allocation). The reason to do this was that the expression IR expands each MoarVM instruction into many IR instructions, and if every IR instruction nodes had to be pointer-based the memory costs would have been significant. But it's still kind of messy.&lt;/li&gt;&lt;li style="text-align: left;"&gt;Some features in MoarVM (like exception handling) rely on being able to identify the section of code which is currently being executed... which is a reasonable choice for an interpreter but not great for compiled code.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style="text-align: left;"&gt;How did we get here?&lt;/h4&gt;&lt;p&gt;One one hand, as a result of my limited experience, time and resources, and on the other hand as a result of the design of MoarVM.&lt;/p&gt;&lt;p&gt;MoarVM was originally designed as a traditional interpreter for a high level language (much like the Perl interpreter). Meaning that it has a large number of different instructions and many instructions operate on high-level data structures like strings, arrays and maps (as opposed to pointers and machine words).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This is by no means a bad or outdated design. Frequently executed routines (string manipulation, hash table lookups etc.) are implemented using an efficient language (C) and driven by a language that is optimized for usability (Raku). This design is also used in modern machine learning frameworks. More importantly, this was a reasonable design because it is a good target for the Rakudo compiler.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For the JIT compiler, this means two things:&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Mapping the large number of VM instructions to machine code (or IR) becomes a significant challenge.&lt;/li&gt;&lt;li&gt;The high level routines and data structures used by the interpreter are mostly opaque to the compiler.&lt;/li&gt;&lt;/ul&gt;&lt;p style="text-align: left;"&gt;The machine code generated by the JIT compiler then will mostly consists of consecutive function calls to VM routines, which is not the type of code where a compiler can really improve performance much. &lt;br /&gt;&lt;/p&gt;&lt;p style="text-align: left;"&gt;In other words, suppose 50% of runtime is spent in interpretation overhead (instruction decoding and dispatch), and 50% is spent in VM routines, then removing interpretation overhead via JIT compilation will at best result in a twofold increase in performance. For many programs, the observed performance increase will be even less.&lt;/p&gt;&lt;p style="text-align: left;"&gt;Mind that I'm specifically refering to the improvement due to machine code generation, and &lt;i&gt;not&lt;/i&gt; to those due to type specialization, inlining etc. (the domain of 'spesh'). These latter features have resulted in much more significant performance improvements.&lt;br /&gt;&lt;/p&gt;&lt;h4 style="text-align: left;"&gt;Was it worth it?&lt;/h4&gt;I think it was.&lt;br /&gt;&lt;p style="text-align: left;"&gt;For me personally, it was a tremendously valuable learning experience which led directly to my current career, writing SQL compilers for Google Cloud.&lt;/p&gt;&lt;p style="text-align: left;"&gt;For the Raku community, even if we never realized the performance improvements that I might have hoped at the start, I hope that the JIT project (as it exists) has been valuable, if for no other reason than identifying the challenges of JIT compilation for MoarVM. A future effort may be able to do better based on what we learned; and I hope my blog posts are a useful resource from that perspective. &lt;br /&gt;&lt;/p&gt;&lt;h4 style="text-align: left;"&gt;What's next?&lt;/h4&gt;&lt;p style="text-align: left;"&gt;Assuming that time and resources were not an issue:&lt;br /&gt;&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li style="text-align: left;"&gt;I'd start by adding tests to the JIT backend. This might take the shape of extracting (parts of) the JIT to a separate project, which MoarVM would link to.&lt;/li&gt;&lt;li style="text-align: left;"&gt;I'd re-engineer the expression IR to be linear ordered instructions, at which point we should be able to construct IR for multiple basic blocks.&lt;/li&gt;&lt;li style="text-align: left;"&gt;I'd deprecate the legacy JIT so we only have one backend left.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If any of this comes to pass, you'll find my report on it right here. Thanks for reasding and until then! &lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;</content>
    <link rel="replies" type="application/atom+xml" href="http://brrt-to-the-future.blogspot.com/feeds/1747613800301306618/comments/default" title="Reacties posten"/>
    <link rel="replies" type="text/html" href="http://brrt-to-the-future.blogspot.com/2023/06/retrospective-of-moarvm-jit.html#comment-form" title="0 reacties"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/1747613800301306618"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/1747613800301306618"/>
    <link rel="alternate" type="text/html" href="http://brrt-to-the-future.blogspot.com/2023/06/retrospective-of-moarvm-jit.html" title="Retrospective of the MoarVM JIT"/>
    <author>
      <name>Bart Wiegmans</name>
      <uri>http://www.blogger.com/profile/05760700924227974153</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry>
    <id>https://5ab5traction5.bearblog.dev/i-raku-easy-subroutine-shortcuts-to-class-constructors/</id>
    <title>I 🫀 Raku - Easy subroutine shortcuts to class constructors</title>
    <updated>2023-02-24T20:01:53.135016+00:00</updated>
    <author>
      <name>5ab5traction5</name>
      <email>hidden</email>
    </author>
    <content type="html"/>
    <link href="https://5ab5traction5.bearblog.dev/i-raku-easy-subroutine-shortcuts-to-class-constructors/" rel="alternate"/>
    <published>2023-01-27T20:21:49.227079+00:00</published>
  </entry>
  <entry>
    <title>The new MoarVM dispatch mechanism is here!</title>
    <link rel="alternate" href="https://6guts.wordpress.com/2021/09/29/the-new-moarvm-dispatch-mechanism-is-here/" type="text/html"/>
    <content type="html">
&lt;p&gt;Around 18 months ago, I set about working on the largest set of architectural changes that Raku runtime MoarVM has seen since its inception. The work was most directly triggered by the realization that we had no good way to fix a certain semantic bug in dispatch without either causing huge performance impacts across the board&amp;nbsp;&lt;em&gt;or&lt;/em&gt;&amp;nbsp;increasingly complexity even further in optimizations that were already riding their luck. However, the need for something like this had been apparent for a while: a persistent struggle to optimize certain Raku language features, the pain of a bunch of performance mechanisms that were all solving the same kind of problem but each for a specific situation, and a sense that, with everything learned since I founded MoarVM, it was possible to do better.&lt;/p&gt;



&lt;p&gt;The result is the development of a new generalized dispatch mechanism. An overview can be found in my Raku Conference talk about it (&lt;a href="https://jnthn.net/papers/2021-trc-dispatch.pdf"&gt;slides&lt;/a&gt;,&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=yRFyGDVHl0E"&gt;video&lt;/a&gt;); in short, it gives us a far more uniform architecture for all kinds of dispatch, allowing us to deliver better performance on a range of language features that have thus far been glacial, as well as opening up opportunities for new optimizations.&lt;/p&gt;



&lt;p&gt;Today, this work has been merged, along with the matching changes in NQP (the Raku subset we use for bootstrapping and to implement the compiler) and Rakudo (the full Raku compiler and standard library implementation). This means that it will ship in the October 2021 releases.&lt;/p&gt;



&lt;p&gt;In this post, I&amp;#8217;ll give an overview of what you can expect to observe right away, and what you might expect in the future as we continue to build upon the possibilities that the new dispatch architecture has to offer.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#the-big-wins"&gt;&lt;/a&gt;The big wins&lt;/h3&gt;



&lt;p&gt;The biggest improvements involve language features that we&amp;#8217;d really not had the architecture to do better on before. They involved dispatch &amp;#8211; that is, getting a call linked to a destination efficiently &amp;#8211; but the runtime didn&amp;#8217;t provide us with a way to &amp;#8220;explain&amp;#8221; to it that it was looking at a dispatch, let alone with the information needed to have a shot at optimizing it.&lt;/p&gt;



&lt;p&gt;The following graph captures a number of these cases, and shows the level of improvement, ranging from a factor of 3.3 to 13.3 times faster.&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img width="601" height="318" data-attachment-id="598" data-permalink="https://6guts.wordpress.com/graph-1/" data-orig-file="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph-1.png" data-orig-size="601,318" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="graph-1" data-image-description="" data-image-caption="" data-medium-file="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph-1.png?w=300" data-large-file="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph-1.png?w=601" src="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph-1.png?w=601" alt="Graph showing benchmark results, described textually below" class="wp-image-598" srcset="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph-1.png 601w, https://6guts.wordpress.com/wp-content/uploads/2021/09/graph-1.png?w=150 150w, https://6guts.wordpress.com/wp-content/uploads/2021/09/graph-1.png?w=300 300w" sizes="(max-width: 601px) 100vw, 601px" /&gt;&lt;/figure&gt;



&lt;p&gt;Let&amp;#8217;s take a quick look at each of these. The first,&amp;nbsp;&lt;code&gt;new-buf&lt;/code&gt;, asks how quickly we can allocate&amp;nbsp;&lt;code&gt;Buf&lt;/code&gt;s.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
for ^10_000_000 {
    Buf.new
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Why is this a dispatch benchmark? Because&amp;nbsp;&lt;code&gt;Buf&lt;/code&gt;&amp;nbsp;is not a class, but rather a role. When we try to make an instance of a role, it is &amp;#8220;punned&amp;#8221; into a class. Up until now, it works as follows:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;We look up the&amp;nbsp;&lt;code&gt;new&lt;/code&gt;&amp;nbsp;method&lt;/li&gt;&lt;li&gt;The&amp;nbsp;&lt;code&gt;find_method&lt;/code&gt;&amp;nbsp;method would, if needed, create a pun of the role and cache it&lt;/li&gt;&lt;li&gt;It would return a forwarding closure that takes the arguments and gives them to the same method called on the punned class, or spelt in Raku code,&amp;nbsp;&lt;code&gt;-&amp;gt; $role-discarded, |args { $pun."$name"(|args) }&lt;/code&gt;&lt;/li&gt;&lt;li&gt;This closure would be invoked with the arguments&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;This had a number of undesirable consequences:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;While the pun was cached, we still had a bit of overhead to check if we&amp;#8217;d made it already&lt;/li&gt;&lt;li&gt;The arguments got slurped and flattened, which costs something, and&amp;#8230;&lt;/li&gt;&lt;li&gt;&amp;#8230;the loss of callsite shape meant we couldn&amp;#8217;t look up a type specialization of the method, and thus lost a chance to inline it too&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;With the new dispatch mechanism, we have a means to cache constants at a given program location&amp;nbsp;&lt;em&gt;and&lt;/em&gt;&amp;nbsp;to replace arguments. So the first time we encounter the call, we:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;Get the role pun produced if needed&lt;/li&gt;&lt;li&gt;Resolve the&amp;nbsp;&lt;code&gt;new&lt;/code&gt;&amp;nbsp;method on the class punned from the role&lt;/li&gt;&lt;li&gt;Produce a dispatch program that caches this resolved method and also replaces the role argument with the pun&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;For the next thousands of calls, we interpret this dispatch program. It&amp;#8217;s still some cost, but the method we&amp;#8217;re calling is already resolved, and the argument list rewriting is fairly cheap. Meanwhile, after we get into some hundreds of iterations, on a background thread, the optimizer gets to work. The argument re-ordering cost goes away completely at this point, and&amp;nbsp;&lt;code&gt;new&lt;/code&gt;&amp;nbsp;is so small it gets inlined &amp;#8211; at which point the buffer allocation is determined dead and so goes away too. Some remaining missed opportunities mean we still are left with a loop that&amp;#8217;s not quite empty: it busies itself making sure it&amp;#8217;s really OK to do nothing, rather than just doing nothing.&lt;/p&gt;



&lt;p&gt;Next up, multiple dispatch with&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi fac($n where $n &amp;lt;= 1) { 1 }
multi fac($n) { $n * fac($n - 1) }
for ^1_000_000 {
    fac(5)
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;These were really slow before, since:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;We couldn&amp;#8217;t apply the multi-dispatch caching mechanism&amp;nbsp;&lt;em&gt;at all&lt;/em&gt;&amp;nbsp;as soon as we had a&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause involved&lt;/li&gt;&lt;li&gt;We would run&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses twice in the event the candidate was chosen: once to see if we should choose that multi candidate, and once again when we entered it&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;With the new mechanism, we:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;On the first call, calculate a multiple dispatch plan: a linked list of candidates to work through&lt;/li&gt;&lt;li&gt;Invoke the one with the&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause, in a mode whereby if the signature fails to bind, it triggers a dispatch resumption. (If it does bind, it runs to completion)&lt;/li&gt;&lt;li&gt;In the event of a bind failure, the dispatch resumption triggers, and we attempt the next candidate&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;Once again, after the setup phase, we interpret the dispatch programs. In fact, that&amp;#8217;s as far as we get with running this faster for now, because the specializer doesn&amp;#8217;t yet know how to translate and further optimize this kind of dispatch program. (That&amp;#8217;s how I know it currently stands no chance of turning this whole thing into another empty loop!) So there&amp;#8217;s more to be had here also; in the meantime, I&amp;#8217;m afraid you&amp;#8217;ll just have to settle for a factor of ten speedup.&lt;/p&gt;



&lt;p&gt;Here&amp;#8217;s the next one:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
proto with-proto(Int $n) { 2 * {*} }
multi with-proto(Int $n) { $n + 1 }
sub invoking-nontrivial-proto() {
    for ^10_000_000 {
        with-proto(20)
    }
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again, on top form, we&amp;#8217;d turn this into an empty loop too, but we don&amp;#8217;t quite get there yet. This case wasn&amp;#8217;t so terrible before: we did get to use the multiple dispatch cache, however to do that we also ended up having to allocate an argument capture. The need for this also blocked any chance of inlining the&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;into the caller. Now that is possible. Since we cannot yet translate dispatch programs that resume an in-progress dispatch, we don&amp;#8217;t yet get to further inline the called&amp;nbsp;&lt;code&gt;multi&lt;/code&gt;&amp;nbsp;candidate into the&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;. However, we now have a design that will let us implement that.&lt;/p&gt;



&lt;p&gt;This whole notion of a dispatch resumption &amp;#8211; where we start doing a dispatch, and later need to access arguments or other pre-calculated data in order to do a next step of it &amp;#8211; has turned out to be a great unification. The initial idea for it came from considering things like&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
class Parent {
    method m() { 1 }
}
class Child is Parent {
    method m() { 1 + callsame }
}
for ^10_000_000 {
    Child.m;
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Once I started looking at this, and then considering that a complex&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;also wants to continue with a dispatch at the&amp;nbsp;&lt;code&gt;{*}&lt;/code&gt;, and in the case a&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses fails in a&amp;nbsp;&lt;code&gt;multi&lt;/code&gt;&amp;nbsp;it&amp;nbsp;&lt;em&gt;also&lt;/em&gt;&amp;nbsp;wants to continue with a dispatch, I realized this was going to be useful for quite a lot of things. It will be a bit of a headache to teach the optimizer and JIT to do nice things with resumes &amp;#8211; but a great relief that doing that once will benefit multiple language features!&lt;/p&gt;



&lt;p&gt;Anyway, back to the benchmark. This is another &amp;#8220;if we were smart, it&amp;#8217;d be an empty loop&amp;#8221; one. Previously,&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;was very costly, because each time we invoked it, it would have to calculate what kind of dispatch we were resuming and the set of methods to call. We also had to be able to locate the arguments. Dynamic variables were involved, which cost a bit to look up too, and &amp;#8211; despite being an implementation details &amp;#8211; these also leaked out in introspection, which wasn&amp;#8217;t ideal. The new dispatch mechanism makes this all rather more efficient: we can cache the calculated set of methods (or wrappers and multi candidates, depending on the context) and then walk through it, and there&amp;#8217;s no dynamic variables involved (and thus no leakage of them). This sees the biggest speedup of the lot &amp;#8211; and since we cannot yet inline away the&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;, it&amp;#8217;s (for now) measuring the speedup one might expect on using this language feature. In the future, it&amp;#8217;s destined to optimize away to an empty loop.&lt;/p&gt;



&lt;p&gt;A module that makes use of&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;on a relatively hot path is&amp;nbsp;&lt;code&gt;OO::Monitors,&lt;/code&gt;, so I figured it would be interesting to see if there is a speedup there also.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
use OO::Monitors;
monitor TestMonitor {
    method m() { 1 }
}
my $mon = TestMonitor.new;
for ^1_000_000 {
    $mon.m();
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;A&amp;nbsp;&lt;code&gt;monitor&lt;/code&gt;&amp;nbsp;is a class that acquires a lock around each method call. The module provides a custom meta-class that adds a lock attribute to the class and then wraps each method such that it acquires the lock. There are certainly costly things in there besides the involvement of&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;, but the improvement to&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;is already enough to see a 3.3x speedup in this benchmark. Since&amp;nbsp;&lt;code&gt;OO::Monitors&lt;/code&gt;&amp;nbsp;is used in quite a few applications and modules (for example, Cro uses it), this is welcome (and yes, a larger improvement will be possible here too).&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#caller-side-decontainerization"&gt;&lt;/a&gt;Caller side decontainerization&lt;/h3&gt;



&lt;p&gt;I&amp;#8217;ve seen some less impressive, but still welcome, improvements across a good number of other microbenchmarks. Even a basic multi dispatch on the&amp;nbsp;&lt;code&gt;+&lt;/code&gt;&amp;nbsp;op:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $i = 0;
for ^10_000_000 {
    $i = $i + $_;
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Comes out with a factor of 1.6x speedup, thanks primarily to us producing far tighter code with fewer guards. Previously, we ended up with duplicate guards in this seemingly straightforward case. The&amp;nbsp;&lt;code&gt;infix:&amp;lt;+&amp;gt;&lt;/code&gt;&amp;nbsp;multi candidate would be specialized for the case of its first argument being an&amp;nbsp;&lt;code&gt;Int&lt;/code&gt;&amp;nbsp;in a&amp;nbsp;&lt;code&gt;Scalar&lt;/code&gt;&amp;nbsp;container and its second argument being an immutable&amp;nbsp;&lt;code&gt;Int&lt;/code&gt;. Since a&amp;nbsp;&lt;code&gt;Scalar&lt;/code&gt;&amp;nbsp;is mutable, the specialization would need to read it and then guard the value read before proceeding, otherwise it may change, and we&amp;#8217;d risk memory safety. When we wanted to inline this candidate, we&amp;#8217;d also want to do a check that the candidate really applies, and so also would deference the&amp;nbsp;&lt;code&gt;Scalar&lt;/code&gt;&amp;nbsp;and guard its content to do that. We can and do eliminate duplicate guards &amp;#8211; but these guards are on two distinct reads of the value, so that wouldn&amp;#8217;t help.&lt;/p&gt;



&lt;p&gt;Since in the new dispatch mechanism we can rewrite arguments, we can now quite easily do caller-side removal of&amp;nbsp;&lt;code&gt;Scalar&lt;/code&gt;&amp;nbsp;containers around values. So easily, in fact, that the change to do it took me just a couple of hours. This gives a lot of benefits. Since dispatch programs automatically eliminate duplicate reads and guards, the read and guard by the multi-dispatcher and the read in order to pass the decontainerized value are coalesced. This means less repeated work prior to specialization and JIT compilation, and also only a single read and guard in the specialized code after it. With the value to be passed already guarded, we can trivially select a candidate taking two bare&amp;nbsp;&lt;code&gt;Int&lt;/code&gt;&amp;nbsp;values, which means there&amp;#8217;s no further reads and guards needed in the callee either.&lt;/p&gt;



&lt;p&gt;A less obvious benefit, but one that will become important with planned future work, is that this means&amp;nbsp;&lt;code&gt;Scalar&lt;/code&gt;&amp;nbsp;containers escape to callees far less often. This creates further opportunities for escape analysis. While the MoarVM escape analyzer and scalar replacer is currently quite limited, I hope to return to working on it in the near future, and expect it will be able to give us even more value now than it would have been able to before.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#further-results"&gt;&lt;/a&gt;Further results&lt;/h3&gt;



&lt;p&gt;The benchmarks shown earlier are mostly of the &amp;#8220;how close are we to realizing that we&amp;#8217;ve got an empty loop&amp;#8221; nature, which is interesting for assessing how well the optimizer can &amp;#8220;see through&amp;#8221; dispatches. Here are a few further results on more &amp;#8220;traditional&amp;#8221; microbenchmarks:&lt;/p&gt;



&lt;figure class="wp-block-image size-large"&gt;&lt;img width="600" height="270" data-attachment-id="599" data-permalink="https://6guts.wordpress.com/graph2/" data-orig-file="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph2.png" data-orig-size="600,270" data-comments-opened="1" data-image-meta="{&amp;quot;aperture&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;credit&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;camera&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;caption&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;created_timestamp&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;copyright&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;focal_length&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;iso&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;shutter_speed&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;title&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;orientation&amp;quot;:&amp;quot;0&amp;quot;}" data-image-title="graph2" data-image-description="" data-image-caption="" data-medium-file="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph2.png?w=300" data-large-file="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph2.png?w=600" src="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph2.png?w=600" alt="Graph showing benchmark results, described textually below" class="wp-image-599" srcset="https://6guts.wordpress.com/wp-content/uploads/2021/09/graph2.png 600w, https://6guts.wordpress.com/wp-content/uploads/2021/09/graph2.png?w=150 150w, https://6guts.wordpress.com/wp-content/uploads/2021/09/graph2.png?w=300 300w" sizes="(max-width: 600px) 100vw, 600px" /&gt;&lt;/figure&gt;



&lt;p&gt;The complex number benchmark is as follows:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $total-re = 0e0;
for ^2_000_000 {
    my $x = 5 + 2i;
    my $y = 10 + 3i;
    my $z = $x * $x + $y;
    $total-re = $total-re + $z.re
}
say $total-re;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That is, just a bunch of operators (multi dispatch) and method calls, where we really do use the result. For now, we&amp;#8217;re tied with Python and a little behind Ruby on this benchmark (and a surprising 48 times faster than the same thing done with Perl&amp;#8217;s&amp;nbsp;&lt;code&gt;Math::Complex&lt;/code&gt;), but this is also a case that stands to see a huge benefit from escape analysis and scalar replacement in the future.&lt;/p&gt;



&lt;p&gt;The hash read benchmark is:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my %h = a =&amp;gt; 10, b =&amp;gt; 12;
my $total = 0;
for ^10_000_000 {
    $total = $total + %h&amp;lt;a&amp;gt; + %h&amp;lt;b&amp;gt;;
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And the hash store one is:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my @keys = 'a'..'z';
for ^500_000 {
    my %h;
    for @keys {
        %h{$_} = 42;
    }
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The improvements are nothing whatsoever to do with hashing itself, but instead look to be mostly thanks to much tighter code all around due to caller-side decontainerization. That can have a secondary effect of bringing things under the size limit for inlining, which is also a big help. Speedup factors of 2x and 1.85x are welcome, although we could really do with the same level of improvement again for me to be reasonably happy with our results.&lt;/p&gt;



&lt;p&gt;The line-reading benchmark is:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $fh = open "longfile";
my $chars = 0;
for $fh.lines { $chars = $chars + .chars };
$fh.close;
say $chars
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again, nothing specific to I/O got faster, but when dispatch &amp;#8211; the glue that puts together all the pieces &amp;#8211; gets a boost, it helps all over the place. (We are also decently competitive on this benchmark, although tend to be slower the moment the UTF-8 decoder can&amp;#8217;t take it&amp;#8217;s &amp;#8220;NFG can&amp;#8217;t possibly apply&amp;#8221; fast path.)&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#and-in-less-micro-things"&gt;&lt;/a&gt;And in less micro things&amp;#8230;&lt;/h3&gt;



&lt;p&gt;I&amp;#8217;ve also started looking at larger programs, and hearing results from others about theirs. It&amp;#8217;s mostly encouraging:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;The long-standing&amp;nbsp;&lt;code&gt;Text::CSV&lt;/code&gt;&amp;nbsp;benchmark&amp;nbsp;&lt;code&gt;test-t&lt;/code&gt;&amp;nbsp;has seen roughly 20% improvement (thanks to lizmat for measuring)&lt;/li&gt;&lt;li&gt;A simple&amp;nbsp;&lt;code&gt;Cro::HTTP&lt;/code&gt;&amp;nbsp;test application gets through about 10% more requests per second&lt;/li&gt;&lt;li&gt;MoarVM contributor dogbert did comparative timings of a number of scripts; the most significant improvement saw a drop from 25s to 7s, most are 10%-30% faster, some without change, and only one that slowed down.&lt;/li&gt;&lt;li&gt;There&amp;#8217;s around 2.5% improvement on compilation of&amp;nbsp;&lt;code&gt;CORE.setting&lt;/code&gt;, the standard library. However, a big pinch of salt is needed here: the compiler itself has changed in a number of places as part of the work, and there were a couple of things tweaked based on looking at profiles that aren&amp;#8217;t really related to dispatch.&lt;/li&gt;&lt;li&gt;Agrammon, an application calculating farming emissions, has seen a slowdown of around 9%. I didn&amp;#8217;t get to look at it closely yet, although glancing at profiling output the number of deoptimizations is relatively high, which suggests we&amp;#8217;re making some poor optimization decisions somewhere.&lt;/li&gt;&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#smaller-profiler-output"&gt;&lt;/a&gt;Smaller profiler output&lt;/h3&gt;



&lt;p&gt;One unpredicted (by me), but also welcome, improvement is that profiler output has become significantly smaller. Likely reasons for this include:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;The dispatch mechanism supports producing value results (either from constants, input arguments, or attributes read from input arguments). It entirely replaces an earlier mechanism, &amp;#8220;specializer plugins&amp;#8221;, which could map guards to a target to invoke, but always required a call to something &amp;#8211; even if that something was the identity function. The logic was that this didn&amp;#8217;t matter for any really hot code, since the identity function will trivially be inlined away. However, since profile size of the instrumenting profiler is a function of the number of paths through the call tree, trimming loads of calls to the identity function out of the tree makes it much smaller.&lt;/li&gt;&lt;li&gt;We used to make lots of calls to the&amp;nbsp;&lt;code&gt;sink&lt;/code&gt;&amp;nbsp;method when a value was in sink context. Now, if we see that the type simply inherits that method from&amp;nbsp;&lt;code&gt;Mu&lt;/code&gt;, we elide the call entirely (again, it would inline away, but a smaller call graph is a smaller profile).&lt;/li&gt;&lt;li&gt;Multiple dispatch caching would previously always call the&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;when the cache was missed, but would then not call an onlystar&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;again when it got cache hits in the future. This meant the call tree under many multiple dispatches was duplicated in the profile. This wasn&amp;#8217;t just a size issue; it was a bit annoying to have this effect show up in the profile reports too.&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;To give an example of the difference, I took profiles from Agrammon to study why it might have become slower. The one from before the dispatcher work weighed in at 87MB; the one with the new dispatch mechanism is under 30MB. That means less memory used while profiling, less time to write the profile out to disk afterwards, and less time for tools to load the profiler output. So now it&amp;#8217;s faster to work out how to make things faster.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#is-there-any-bad-news"&gt;&lt;/a&gt;Is there any bad news?&lt;/h3&gt;



&lt;p&gt;I&amp;#8217;m afraid so. Startup time has suffered. While the new dispatch mechanism is more powerful, pushes more complexity out of the VM into high level code, and is more conducive to reaching higher peak performance, it also has a higher warmup time. At the time of writing, the impact on startup time seems to be around 25%. I expect we can claw some of that back ahead of the October release.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#what-will-be-broken"&gt;&lt;/a&gt;What will be broken?&lt;/h3&gt;



&lt;p&gt;Changes of this scale always come with an amount of risk. We&amp;#8217;re merging this some weeks ahead of the next scheduled monthly release in order to have time for more testing, and to address any regressions that get reported. However, even before reaching the point of merging it, we have:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Ensured it passes the specification test suite, both in normal circumstances, but also under optimizer stressing (where we force it to prematurely optimize everything, so that we tease out optimizer bugs and &amp;#8211; given how many poor decisions we force it to make &amp;#8211; deoptimization bugs too)&lt;/li&gt;&lt;li&gt;Used&amp;nbsp;&lt;code&gt;blin&lt;/code&gt;&amp;nbsp;to run the tests of ecosystem modules. This is a standard step when preparing Rakudo releases, but in this case we&amp;#8217;ve aimed it at the&amp;nbsp;&lt;code&gt;new-disp&lt;/code&gt;&amp;nbsp;branches. This found a number of regressions caused by the switch to the new dispatch mechanism, which have been addressed.&lt;/li&gt;&lt;li&gt;Patched or sent pull requests to a number of modules that were relying on unsupported internal APIs that have now gone away or changed, or on other implementation details. There were relatively few of these, and happily, many of them were fixed up by migrating to supported APIs (which likely didn&amp;#8217;t exist at the time the modules were written).&lt;/li&gt;&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#what-happens-next"&gt;&lt;/a&gt;What happens next?&lt;/h3&gt;



&lt;p&gt;As I&amp;#8217;ve alluded to in a number of places in this post, while there are improvements to be enjoyed right away, there are also new opportunities for further improvement. Some things that are on my mind include:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Reworking callframe entry and exit. These are still decidedly too costly. Various changes that have taken place while working on the new dispatch mechanism have opened up new opportunities for improvement in this area.&lt;/li&gt;&lt;li&gt;Avoiding megamorphic pile-ups. Micro-benchmarks are great at hiding these. In fact, the&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;one here is a perfect example! The point we do the resumption of a dispatch is inside&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;, so all the inline cache entries of resumptions throughout the program stack up in one place. What we&amp;#8217;d like is to have them attached a level down the callstack instead. Otherwise, the level of&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;improvement seen in micro-benchmarks will not be enjoyed in larger applications. This applies in a number of other situations too.&lt;/li&gt;&lt;li&gt;Applying the new dispatch mechanism to optimize further constructs. For example, a method call that results in invoking the special&amp;nbsp;&lt;code&gt;FALLBACK&lt;/code&gt;&amp;nbsp;method could have its callsite easily rewritten to do that, opening the way to inlining.&lt;/li&gt;&lt;li&gt;Further tuning the code we produce after optimization. There is an amount of waste that should be relatively straightforward to eliminate, and some opportunities to tweak deoptimization such that we&amp;#8217;re able to delete more instructions and still retain the ability to deoptimize.&lt;/li&gt;&lt;li&gt;Continuing with the escape analysis work I was doing before, which should now be rather more valuable. The more flexible callstack/frame handling in place should also unblock my work on scalar replacement of&amp;nbsp;&lt;code&gt;Int&lt;/code&gt;s (which needs a great deal of care in memory management, as they may box a big integer, not just a native integer).&lt;/li&gt;&lt;li&gt;Implementing specialization, JIT, and inlining of dispatch resumptions.&lt;/li&gt;&lt;/ul&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/a894b2e9496ef54d2ad1fbbe60b95010#thank-you"&gt;&lt;/a&gt;Thank you&lt;/h3&gt;



&lt;p&gt;I would like to thank&amp;nbsp;&lt;a href="https://www.perlfoundation.org/"&gt;TPF&lt;/a&gt;&amp;nbsp;and their donors for providing the funding that has made it possible for me to spend a good amount of my working time on this effort.&lt;/p&gt;



&lt;p&gt;While I&amp;#8217;m to blame for the overall design and much of the implementation of the new dispatch mechanism, plenty of work has also been put in by other MoarVM and Rakudo contributors &amp;#8211; especially over the last few months as the final pieces fell into place, and we turned our attention to getting it production ready. I&amp;#8217;m thankful to them not only for the code and debugging contributions, but also much support and encouragement along the way. It feels good to have this merged, and I look forward to building upon it in the months and years to come.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">Around 18 months ago, I set about working on the largest set of architectural changes that Raku runtime MoarVM has seen since its inception. The work was most directly triggered by the realization that we had no good way to … <a href="https://6guts.wordpress.com/2021/09/29/the-new-moarvm-dispatch-mechanism-is-here/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>jnthnwrthngtn</name>
    </author>
    <id>http://6guts.wordpress.com/?p=596</id>
    <published>2021-09-29T16:16:31Z</published>
    <updated>2021-09-29T16:16:31Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>Raku multiple dispatch with the new MoarVM dispatcher</title>
    <link rel="alternate" href="https://6guts.wordpress.com/2021/04/15/raku-multiple-dispatch-with-the-new-moarvm-dispatcher/" type="text/html"/>
    <content type="html">
&lt;p&gt;I recently wrote about the&amp;nbsp;&lt;a href="https://6guts.wordpress.com/2021/03/15/towards-a-new-general-dispatch-mechanism-in-moarvm/"&gt;new MoarVM dispatch mechanism&lt;/a&gt;, and in that post noted that I still had a good bit of Raku&amp;#8217;s multiple dispatch semantics left to implement in terms of it. Since then, I&amp;#8217;ve made a decent amount of progress in that direction. This post contains an overview of the approach taken, and some very rough performance measurements.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#my-goodness-thats-a-lot-of-semantics"&gt;&lt;/a&gt;My goodness, that&amp;#8217;s a lot of semantics&lt;/h3&gt;



&lt;p&gt;Of all the kinds of dispatch we find in Raku, multiple dispatch is the most complex. Multiple dispatch allows us to write a set of candidates, which are then selected by the number of arguments:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi ok($condition, $desc) {
    say ($condition ?? 'ok' !! 'not ok') ~ " - $desc";
}
multi ok($condition) {
    ok($condition, '');
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Or the types of arguments:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi to-json(Int $i) { ~$i }
multi to-json(Bool $b) { $b ?? 'true' !! 'false' }
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And not just one argument, but potentially many:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi truncate(Str $str, Int $chars) {
    $str.chars &amp;lt; $chars ?? $str !! $str.substr(0, $chars) ~ '...'
}
multi truncate(Str $str, Str $after) {
    with $str.index($after) -&amp;gt; $pos {
        $str.substr(0, $pos) ~ '...'
    }
    else {
        $str
    }
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We may write&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses to differentiate candidates on properties that are not captured by nominal types:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi fac($n where $n &amp;lt;= 1) { 1 }
multi fac($n) { $n * fac($n - 1) }
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Every time we write a set of&amp;nbsp;&lt;code&gt;multi&lt;/code&gt;&amp;nbsp;candidates like this, the compiler will automatically produce a&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;routine. This is what is installed in the symbol table, and holds the candidate list. However, we can also write our own&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;, and use the special term&amp;nbsp;&lt;code&gt;{*}&lt;/code&gt;&amp;nbsp;to decide at which point we do the dispatch, if at all.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
proto mean($collection) {
    $collection.elems == 0 ?? Nil !! {*}
}
multi mean(@arr) {
    @arr.sum / @arr.elems
}
multi mean(%hash) {
    %hash.values.sum / %hash.elems
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Candidates are ranked by narrowness (using topological sorting). If multiple candidates match, but they are equally narrow, then that&amp;#8217;s an ambiguity error. Otherwise, we call narrowest one. The candidate we choose may then use&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;and friends to defer to the next narrowest candidate, which may do the same, until we reach the most general matching one.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#multiple-dispatch-is-everywhere"&gt;&lt;/a&gt;Multiple dispatch is everywhere&lt;/h3&gt;



&lt;p&gt;Raku leans heavily on multiple dispatch. Most operators in Raku are compiled into calls to multiple dispatch subroutines. Even&amp;nbsp;&lt;code&gt;$a + $b&lt;/code&gt;&amp;nbsp;will be a multiple dispatch. This means doing multiple dispatch efficiently is really important for performance. Given the riches of its semantics, this is potentially a bit concerning. However, there&amp;#8217;s good news too.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#most-multiple-dispatches-are-boring"&gt;&lt;/a&gt;Most multiple dispatches are boring&lt;/h3&gt;



&lt;p&gt;The overwhelmingly common case is that we have:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;A decision made only by the number of arguments and nominal types&lt;/li&gt;&lt;li&gt;No&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses&lt;/li&gt;&lt;li&gt;No custom&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&lt;/li&gt;&lt;li&gt;No&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;This isn&amp;#8217;t to say the other cases are unimportant; they are really quite useful, and it&amp;#8217;s desirable for them to perform well. However, it&amp;#8217;s also desirable to make what savings we can in the common case. For example, we don&amp;#8217;t want to eagerly calculate the full set of possible candidates for every single multiple dispatch, because the majority of the time only the first one matters. This is not just a time concern: recall that the new dispatch mechanism stores dispatch programs at each callsite, and if we store the list of all matching candidates at each of those, we&amp;#8217;ll waste a lot of memory too.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#how-do-we-do-today"&gt;&lt;/a&gt;How do we do today?&lt;/h3&gt;



&lt;p&gt;The situation in Rakudo today is as follows:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;If the dispatch is decided by arity and nominal type only, and you don&amp;#8217;t call it with flattening args, it&amp;#8217;ll probably perform quite decently, and perhaps even enjoy inlining of the candidate and elimination of duplicate type checks that would take place on the slow path. This is thanks to the&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;holding a &amp;#8220;dispatch cache&amp;#8221;, a special-case mechanism implemented in the VM that uses a search tree, with one level per argument.&lt;/li&gt;&lt;li&gt;If that&amp;#8217;s the case but it has a custom&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;, it&amp;#8217;s not too bad either, though inlining isn&amp;#8217;t going to be happening; it can still use the search tree, though&lt;/li&gt;&lt;li&gt;If it uses&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses, it&amp;#8217;ll be slow, because the search tree only deals in finding one candidate per set of nominal types, and so we can&amp;#8217;t use it&lt;/li&gt;&lt;li&gt;The same reasoning applies to&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;; it&amp;#8217;ll be slow too&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;Effectively, the situation today is that you simply&amp;nbsp;&lt;em&gt;don&amp;#8217;t&lt;/em&gt;&amp;nbsp;use&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses in a multiple dispatch if its anywhere near a hot path (well, and if you know where the hot paths are, and know that this kind of dispatch is slow). Ditto for&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;, although that&amp;#8217;s less commonly reached for. The question is, can we do better with the new dispatcher?&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#guard-the-types"&gt;&lt;/a&gt;Guard the types&lt;/h3&gt;



&lt;p&gt;Let&amp;#8217;s start out with seeing how the simplest cases are dealt with, and build from there. (This is actually what I did in terms of the implementation, but at the same time I had a rough idea where I was hoping to end up.)&lt;/p&gt;



&lt;p&gt;Recall this pair of candidates:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi truncate(Str $str, Int $chars) {
    $str.chars &amp;lt; $chars ?? $str !! $str.substr(0, $chars) ~ '...'
}
multi truncate(Str $str, Str $after) {
    with $str.index($after) -&amp;gt; $pos {
        $str.substr(0, $pos) ~ '...'
    }
    else {
        $str
    }
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We then have a call&amp;nbsp;&lt;code&gt;truncate($message, "\n")&lt;/code&gt;, where&amp;nbsp;&lt;code&gt;$message&lt;/code&gt;&amp;nbsp;is a&amp;nbsp;&lt;code&gt;Str&lt;/code&gt;. Under the new dispatch mechanism, the call is made using the&amp;nbsp;&lt;code&gt;raku-call&lt;/code&gt;&amp;nbsp;dispatcher, which identifies that this is a multiple dispatch, and thus delegates to&amp;nbsp;&lt;code&gt;raku-multi&lt;/code&gt;. (Multi-method dispatch ends up there too.)&lt;/p&gt;



&lt;p&gt;The record phase of the dispatch &amp;#8211; on the first time we reach this callsite &amp;#8211; will proceed as follows:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;Iterate over the candidates&lt;/li&gt;&lt;li&gt;If a candidate doesn&amp;#8217;t match on argument count, just discard it. Since the shape of a callsite is a constant, and we calculate dispatch programs at each callsite, we don&amp;#8217;t need to establish any guards for this.&lt;/li&gt;&lt;li&gt;If it matches on types and concreteness, note which parameters are involved and what kinds of guards they need.&lt;/li&gt;&lt;li&gt;If there was no match or an ambiguity, report the error without producing a dispatch program.&lt;/li&gt;&lt;li&gt;Otherwise, having established the type guards, delegate to the&amp;nbsp;&lt;code&gt;raku-invoke&lt;/code&gt;&amp;nbsp;dispatcher with the chosen candidate.&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;When we reach the same callsite again, we can run the dispatch program, which quickly checks if the argument types match those we saw last time, and if they do, we know which candidate to invoke. These checks are very cheap &amp;#8211; far cheaper than walking through all of the candidates and examining each of them for a match. The optimizer may later be able to prove that the checks will always come out true and eliminate them.&lt;/p&gt;



&lt;p&gt;Thus the whole of the dispatch processes &amp;#8211; at least for this simple case where we only have types and arity &amp;#8211; can be &amp;#8220;explained&amp;#8221; to the virtual machine as &amp;#8220;if the arguments have these exact types, invoke this routine&amp;#8221;. It&amp;#8217;s pretty much the same as we were doing for method dispatch, except there we only cared about the type of the first argument &amp;#8211; the invocant &amp;#8211; and the value of the method name. (Also recall from the previous post that if it&amp;#8217;s a multi-method dispatch, then both method dispatch and multiple dispatch will guard the type of the first argument, but the duplication is eliminated, so only one check is done.)&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#that-goes-in-the-resumption-hole"&gt;&lt;/a&gt;That goes in the resumption hole&lt;/h3&gt;



&lt;p&gt;Coming up with good abstractions is difficult, and therein lies much of the challenge of the new dispatch mechanism. Raku has quite a number of different dispatch-like things. However, encoding all of them directly in the virtual machine leads to high complexity, which makes building reliable optimizations (or even reliable unoptimized implementations!) challenging. Thus the aim is to work out a comparatively small set of primitives that allow for dispatches to be &amp;#8220;explained&amp;#8221; to the virtual machine in such a way that it can deliver decent performance.&lt;/p&gt;



&lt;p&gt;It&amp;#8217;s fairly clear that&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;is a kind of dispatch resumption, but what about the custom&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;case and the&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause case? It turns out that these can both be neatly expressed in terms of dispatch resumption too (the&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause case needing one small addition at the virtual machine level, which in time is likely to be useful for other things too). Not only that, but encoding these features in terms of dispatch resumption is also quite direct, and thus should be efficient. Every trick we teach the specializer about doing better with dispatch resumptions can benefit all of the language features that are implemented using them, too.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#custom-protos"&gt;&lt;/a&gt;Custom protos&lt;/h3&gt;



&lt;p&gt;Recall this example:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
proto mean($collection) {
    $collection.elems == 0 ?? Nil !! {*}
}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here, we want to run the body of the&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;, and then proceed to the chosen candidate at the point of the&amp;nbsp;&lt;code&gt;{*}&lt;/code&gt;. By contrast, when we don&amp;#8217;t have a custom&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;, we&amp;#8217;d like to simply get on with calling the correct&amp;nbsp;&lt;code&gt;multi&lt;/code&gt;.&lt;/p&gt;



&lt;p&gt;To achieve this, I first moved the multi candidate selection logic from the&amp;nbsp;&lt;code&gt;raku-multi&lt;/code&gt;&amp;nbsp;dispatcher to the&amp;nbsp;&lt;code&gt;raku-multi-core&lt;/code&gt;&amp;nbsp;dispatcher. The&amp;nbsp;&lt;code&gt;raku-multi&lt;/code&gt;&amp;nbsp;dispatcher then checks if we have an &amp;#8220;onlystar&amp;#8221;&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;(one that does not need us to run it). If so, it delegates immediately to&amp;nbsp;&lt;code&gt;raku-multi-core&lt;/code&gt;. If not, it saves the arguments to the dispatch as the resumption initialization state, and then calls the&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;. The&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;#8216;s&amp;nbsp;&lt;code&gt;{*}&lt;/code&gt;&amp;nbsp;is compiled into a dispatch resumption. The resumption then delegates to&amp;nbsp;&lt;code&gt;raku-multi-core&lt;/code&gt;. Or, in code:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-multi',
    # Initial dispatch, only setting up resumption if we need to invoke the
    # proto.
    -&amp;gt; $capture {
        my $callee := nqp::captureposarg($capture, 0);
        my int $onlystar := nqp::getattr_i($callee, Routine, '$!onlystar');
        if $onlystar {
            # Don't need to invoke the proto itself, so just get on with the
            # candidate dispatch.
            nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi-core', $capture);
        }
        else {
            # Set resume init args and run the proto.
            nqp::dispatch('boot-syscall', 'dispatcher-set-resume-init-args', $capture);
            nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke', $capture);
        }
    },
    # Resumption means that we have reached the {*} in the proto and so now
    # should go ahead and do the dispatch. Make sure we only do this if we
    # are signalled to that it's a resume for an onlystar (resumption kind 5).
    -&amp;gt; $capture {
        my $track_kind := nqp::dispatch('boot-syscall', 'dispatcher-track-arg', $capture, 0);
        nqp::dispatch('boot-syscall', 'dispatcher-guard-literal', $track_kind);
        my int $kind := nqp::captureposarg_i($capture, 0);
        if $kind == 5 {
            nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi-core',
                nqp::dispatch('boot-syscall', 'dispatcher-get-resume-init-args'));
        }
        elsif !nqp::dispatch('boot-syscall', 'dispatcher-next-resumption') {
            nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'boot-constant',
                nqp::dispatch('boot-syscall', 'dispatcher-insert-arg-literal-obj',
                    $capture, 0, Nil));
        }
    });
&lt;/pre&gt;&lt;/div&gt;


&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#two-become-one"&gt;&lt;/a&gt;Two become one&lt;/h3&gt;



&lt;p&gt;Deferring to the next candidate (for example with&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;) and trying the next candidate because a&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause failed look very similar: both involve walking through a list of possible candidates. There&amp;#8217;s some details, but they have a great deal in common, and it&amp;#8217;d be nice if that could be reflected in how multiple dispatch is implemented using the new dispatcher.&lt;/p&gt;



&lt;p&gt;Before that, a slightly terrible detail about how things work in Rakudo today when we have&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses. First, the dispatcher does a &amp;#8220;trial bind&amp;#8221;, where it asks the question: would this signature bind? To do this, it has to evaluate all of the&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses. Worse, it has to use the slow-path signature binder too, which interprets the signature, even though we can in many cases compile it. If the candidate matches, great, we select it, and then invoke it&amp;#8230;which runs the&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses a second time, as part of the compiled signature binding code. There is nothing efficient about this at all, except for it being by far more efficient on developer time, which is why it happened that way.&lt;/p&gt;



&lt;p&gt;Anyway, it goes without saying that I&amp;#8217;m rather keen to avoid this duplicate work&amp;nbsp;&lt;em&gt;and&lt;/em&gt;&amp;nbsp;the slow-path binder where possible as I re-implement this using the new dispatcher. And, happily, a small addition provides a solution. There is an op&amp;nbsp;&lt;code&gt;assertparamcheck&lt;/code&gt;, which any kind of parameter checking compiles into (be it type checking,&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause checking, etc.) This triggers a call to a function that gets the arguments, the thing we were trying to call, and can then pick through them to produce an error message. The trick is to provide a way to invoke a routine such that a bind failure, instead of calling the error reporting function, will leave the routine and then do a dispatch resumption! This means we can turn failure to pass&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause checks into a dispatch resumption, which will then walk to the next candidate and try it instead.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#trivial-vs-non-trivial"&gt;&lt;/a&gt;Trivial vs. non-trivial&lt;/h3&gt;



&lt;p&gt;This gets us most of the way to a solution, but there&amp;#8217;s still the question of being memory and time efficient in the common case, where there is no resumption and no&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses. I coined the term &amp;#8220;trivial multiple dispatch&amp;#8221; for this situation, which makes the other situation &amp;#8220;non-trivial&amp;#8221;. In fact, I even made a dispatcher called&amp;nbsp;&lt;code&gt;raku-multi-non-trivial&lt;/code&gt;! There are two ways we can end up there.&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;The initial attempt to find a matching candidate determines that we&amp;#8217;ll have to consider&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses. As soon as we see this is the case, we go ahead and produce a full list of possible candidates that could match. This is a linked list (see my previous post for why).&lt;/li&gt;&lt;li&gt;The initial attempt to find a matching candidate finds one that can be picked based purely on argument count and nominal types. We stop there, instead of trying to build a full candidate list, and run the matching candidate. In the event that a&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;happens, we end up in the trivial dispatch resumption handler, which &amp;#8211; since this situation is now non-trivial &amp;#8211; builds the full candidate list, snips the first item off it (because we already ran that), and delegates to&amp;nbsp;&lt;code&gt;raku-multi-non-trivial&lt;/code&gt;.&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;Lost in this description is another significant improvement: today, when there are&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses, we entirely lose the ability to use the MoarVM multiple dispatch cache, but under the new dispatcher, we store a type-filtered list of candidates at the callsite, and then cheap type guards are used to check it is valid to use.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#preliminary-results"&gt;&lt;/a&gt;Preliminary results&lt;/h3&gt;



&lt;p&gt;I did a few benchmarks to see how the new dispatch mechanism did with a couple of situations known to be sub-optimal in Rakudo today. These numbers do not reflect what is&amp;nbsp;&lt;em&gt;possible&lt;/em&gt;, because at the moment the specializer does not have much of an understanding of the new dispatcher. Rather, they reflect the&amp;nbsp;&lt;em&gt;minimal&lt;/em&gt;&amp;nbsp;improvement we can expect.&lt;/p&gt;



&lt;p&gt;Consider this benchmark using a&amp;nbsp;&lt;code&gt;multi&lt;/code&gt;&amp;nbsp;with a&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clause to recursively implement factorial.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi fac($n where $n &amp;lt;= 1) { 1 }
multi fac($n) { $n * fac($n - 1) }
for ^100_000 {
    fac(10)
}
say now - INIT now;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This needs some tweaks (and to be run under an environment variable) to use the new dispatcher; these are temporary, until such a time I switch Rakudo over to using the new dispatcher by default:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
use nqp;
multi fac($n where $n &amp;lt;= 1) { 1 }
multi fac($n) { $n * nqp::dispatch('raku-call', &amp;amp;fac, $n - 1) }
for ^100_000 {
    nqp::dispatch('raku-call', &amp;amp;fac, 10);
}
say now - INIT now;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;On my machine, the first runs in 4.86s, the second in 1.34s. Thus under the new dispatcher this runs in little over a quarter of the time it used to &amp;#8211; a quite significant improvement already.&lt;/p&gt;



&lt;p&gt;A case involving&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;is also interesting to consider. Here it is without using the new dispatcher:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi fallback(Any $x) { "a$x" }
multi fallback(Numeric $x) { "n" ~ callsame }
multi fallback(Real $x) { "r" ~ callsame }
multi fallback(Int $x) { "i" ~ callsame }
for ^1_000_000 {
    fallback(4+2i);
    fallback(4.2);
    fallback(42);
}   
say now - INIT now;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And with the temporary tweaks to use the new dispatcher:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
use nqp;
multi fallback(Any $x) { "a$x" }
multi fallback(Numeric $x) { "n" ~ new-disp-callsame }
multi fallback(Real $x) { "r" ~ new-disp-callsame }
multi fallback(Int $x) { "i" ~ new-disp-callsame }
for ^1_000_000 {
    nqp::dispatch('raku-call', &amp;amp;fallback, 4+2i);
    nqp::dispatch('raku-call', &amp;amp;fallback, 4.2);
    nqp::dispatch('raku-call', &amp;amp;fallback, 42);
}
say now - INIT now;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;On my machine, the first runs in 31.3s, the second in 11.5s, meaning that with the new dispatcher we manage it in a little over a third of the time that current Rakudo does.&lt;/p&gt;



&lt;p&gt;These are both quite encouraging, but as previously mentioned, a majority of multiple dispatches are of the trivial kind, not using these features. If I make the most common case worse on the way to making other things better, that would be bad. It&amp;#8217;s not yet possible to make a fair comparison of this: trivial multiple dispatches already receive a lot of attention in the specializer, and it doesn&amp;#8217;t yet optimize code using the new dispatcher well. Of note, in an example like this:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
multi m(Int) { }
multi m(Str) { }
for ^1_000_000 {
    m(1);
    m("x");
}
say now - INIT now;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Inlining and other optimizations will turn this into an empty loop, which is hard to beat. There is one thing we can already do, though: run it with the specializer disabled. The new dispatcher version looks like this:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
use nqp;
multi m(Int) { }
multi m(Str) { }
for ^1_000_000 {
    nqp::dispatch('raku-call', &amp;amp;m, 1);
    nqp::dispatch('raku-call', &amp;amp;m, "x");
}
say now - INIT now;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The results are 0.463s and 0.332s respectively. Thus, the baseline execution time &amp;#8211; before the specializer does its magic &amp;#8211; is less using the new general dispatch mechanism than it is using the special-case multiple dispatch cache that we currently use. I wasn&amp;#8217;t sure what to expect here before I did the measurement. Given we&amp;#8217;re going from a specialized mechanism that has been profiled and tweaked to a new general mechanism that hasn&amp;#8217;t received such attention, I was quite ready to be doing a little bit worse initially, and would have been happy with parity. Running in 70% of the time was a bigger improvement than I expected at this point.&lt;/p&gt;



&lt;p&gt;I expect that once the specializer understands the new dispatch mechanism better, it will be able to also turn the above into an empty loop &amp;#8211; however, since more iterations can be done per-optimization, this should still show up as a win for the new dispatcher.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/20be85843ca5d903e50e3b87c1cefde5#final-thoughts"&gt;&lt;/a&gt;Final thoughts&lt;/h3&gt;



&lt;p&gt;With one relatively small addition, the new dispatch mechanism is already handling most of the Raku multiple dispatch semantics. Furthermore, even without the specializer and JIT really being able to make a good job of it, some microbenchmarks already show a factor of 3x-4x improvement. That&amp;#8217;s a pretty good starting point.&lt;/p&gt;



&lt;p&gt;There&amp;#8217;s still a good bit to do before we ship a Rakudo release using the new dispatcher. However, multiple dispatch was the biggest remaining threat to the design: it&amp;#8217;s rather more involved than other kinds of dispatch, and it was quite possible that an unexpected shortcoming could trigger another round of design work, or reveal that the general mechanism was going to struggle to perform compared to the more specialized one in the baseline unoptimized, case. So far, there&amp;#8217;s no indication of either of these, and I&amp;#8217;m cautiously optimistic that the overall design is about right.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">I recently wrote about the new MoarVM dispatch mechanism, and in that post noted that I still had a good bit of Raku’s multiple dispatch semantics left to implement in terms of it. Since then, I’ve made a decent amount of … <a href="https://6guts.wordpress.com/2021/04/15/raku-multiple-dispatch-with-the-new-moarvm-dispatcher/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>jnthnwrthngtn</name>
    </author>
    <id>http://6guts.wordpress.com/?p=589</id>
    <published>2021-04-15T09:54:30Z</published>
    <updated>2021-04-15T09:54:30Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>Towards a new general dispatch mechanism in MoarVM</title>
    <link rel="alternate" href="https://6guts.wordpress.com/2021/03/15/towards-a-new-general-dispatch-mechanism-in-moarvm/" type="text/html"/>
    <content type="html">
&lt;p&gt;My goodness, it appears I&amp;#8217;m writing my first Raku internals blog post in over two years. Of course, two years ago it wasn&amp;#8217;t even called Raku. Anyway, without further ado, let&amp;#8217;s get on with this shared brainache.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#what-is-dispatch"&gt;&lt;/a&gt;What is dispatch?&lt;/h3&gt;



&lt;p&gt;I use &amp;#8220;dispatch&amp;#8221; to mean a process by which we take a set of arguments and end up with some action being taken based upon them. Some familiar examples include:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Making a method call, such as&amp;nbsp;&lt;code&gt;$basket.add($product, $quantity)&lt;/code&gt;. We might traditionally call just&amp;nbsp;&lt;code&gt;$product&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;$qauntity&lt;/code&gt;&amp;nbsp;the arguments, but for my purposes, all of&amp;nbsp;&lt;code&gt;$basket&lt;/code&gt;, the method name&amp;nbsp;&lt;code&gt;'add'&lt;/code&gt;,&amp;nbsp;&lt;code&gt;$product&lt;/code&gt;, and&amp;nbsp;$quantity` are arguments to the dispatch: they are the things we need in order to make a decision about what we&amp;#8217;re going to do.&lt;/li&gt;&lt;li&gt;Making a subroutine call, such as&amp;nbsp;&lt;code&gt;uc($youtube-comment)&lt;/code&gt;. Since Raku sub calls are lexically resolved, in this case the arguments to the dispatch are&amp;nbsp;&lt;code&gt;&amp;amp;uc&lt;/code&gt;&amp;nbsp;(the result of looking up the subroutine) and&amp;nbsp;&lt;code&gt;$youtube-comment&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Calling a multiple dispatch subroutine or method, where the number and types of the arguments are used in order to decide which of a set of candidates is to be invoked. This process could be seen as taking place &amp;#8220;inside&amp;#8221; of one of the above two dispatches, given we have both multiple dispatch subroutines and methods in Raku.&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;At first glance, perhaps the first two seem fairly easy and the third a bit more of a handful &amp;#8211; which is sort of true. However, Raku has a number of other features that make dispatch rather more, well, interesting. For example:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;code&gt;wrap&lt;/code&gt;&amp;nbsp;allows us to wrap any&amp;nbsp;&lt;code&gt;Routine&lt;/code&gt;&amp;nbsp;(sub or method); the wrapper can then choose to defer to the original routine, either with the original arguments or with new arguments&lt;/li&gt;&lt;li&gt;When doing multiple dispatch, we may write a&amp;nbsp;&lt;code&gt;proto&lt;/code&gt;&amp;nbsp;routine that gets to choose when &amp;#8211; or even if &amp;#8211; the call to the appropriate candidate is made&lt;/li&gt;&lt;li&gt;We can use routines like&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;in order to defer to the next candidate in the dispatch. But what does that mean? If we&amp;#8217;re in a multiple dispatch, it would mean the next most applicable candidate, if any. If we&amp;#8217;re in a method dispatch then it means a method from a base class. (The same thing is used to implement going to the next wrapper or, eventually, to the originally wrapped routine too). And these can be combined: we can wrap a multi method, meaning we can have 3 levels of things that all potentially contribute the next thing to call!&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;Thanks to this, dispatch &amp;#8211; at least in Raku &amp;#8211; is not always something we do and produce an outcome, but rather a process that we may be asked to continue with multiple times!&lt;/p&gt;



&lt;p&gt;Finally, while the examples I&amp;#8217;ve written above can all quite clearly be seen as examples of dispatch, a number of other common constructs in Raku can be expressed as a kind of dispatch too. Assignment is one example: the semantics of it depend on the target of the assignment and the value being assigned, and thus we need to pick the correct semantics. Coercion is another example, and return value type-checking yet another.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#why-does-dispatch-matter"&gt;&lt;/a&gt;Why does dispatch matter?&lt;/h3&gt;



&lt;p&gt;Dispatch is everywhere in our programs, quietly tieing together the code that wants stuff done with the code that does stuff. Its ubiquity means it plays a significant role in program performance. In the best case, we can reduce the cost to zero. In the worst case, the cost of the dispatch is high enough to exceed that of the work done as a result of the dispatch.&lt;/p&gt;



&lt;p&gt;To a first approximation, when the runtime &amp;#8220;understands&amp;#8221; the dispatch the performance tends to be at least somewhat decent, but when it doesn&amp;#8217;t there&amp;#8217;s a high chance of it being awful. Dispatches tend to involve an amount of work that can be cached, often with some cheap guards to verify the validity of the cached outcome. For example, in a method dispatch, naively we need to walk a linearization of the inheritance graph and ask each class we encounter along the way if it has a method of the specified name. Clearly, this is not going to be terribly fast if we do it on every method call. However, a particular method name on a particular type (identified precisely, without regard to subclassing) will resolve to the same method each time. Thus, we can cache the outcome of the lookup, and use it whenever the type of the invocant matches that used to produce the cached result.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#specialized-vs-generalized-mechanisms-in-language-runtimes"&gt;&lt;/a&gt;Specialized vs. generalized mechanisms in language runtimes&lt;/h3&gt;



&lt;p&gt;When one starts building a runtime aimed at a particular language, and has to do it on a pretty tight budget, the most obvious way to get somewhat tolerable performance is to bake various hot-path language semantics into the runtime. This is exactly how MoarVM started out. Thus, if we look at MoarVM as it stood several years ago, we find things like:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Some support for method caching&lt;/li&gt;&lt;li&gt;A multi-dispatch cache highly tied to Raku&amp;#8217;s multi-dispatch semantics, and only really able to help when the dispatch is all about nominal types (so using&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;comes at a very high cost)&lt;/li&gt;&lt;li&gt;A mechanism for specifying how to find the actual code handle inside of a wrapping code object (for example, a&amp;nbsp;&lt;code&gt;Sub&lt;/code&gt;&amp;nbsp;object has a private attribute in it that holds the low-level code handle identifying the bytecode to run)&lt;/li&gt;&lt;li&gt;Some limited attempts to allow us to optimize correctly in the case we know that a dispatch will not be continued &amp;#8211; which requires careful cooperation between compiler and runtime (or less diplomatically, it&amp;#8217;s all a big hack)&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;These are all still there today, however are also all on the way out. What&amp;#8217;s most telling about this list is what&amp;nbsp;&lt;em&gt;isn&amp;#8217;t&lt;/em&gt;&amp;nbsp;included. Things like:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Private method calls, which would need a different cache &amp;#8211; but the initial VM design limited us to one per type&lt;/li&gt;&lt;li&gt;Qualified method calls (&lt;code&gt;$obj.SomeType::method-name()&lt;/code&gt;)&lt;/li&gt;&lt;li&gt;Ways to decently optimize dispatch resumption&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;A few years back I started to partially address this, with the introduction of a mechanism I called &amp;#8220;specializer plugins&amp;#8221;. But first, what is the specializer?&lt;/p&gt;



&lt;p&gt;When MoarVM started out, it was a relatively straightforward interpreter of bytecode. It only had to be fast enough to beat the Parrot VM in order to get a decent amount of usage, which I saw as important to have before going on to implement some more interesting optimizations (back then we didn&amp;#8217;t have the kind of pre-release automated testing infrastructure we have today, and so depended much more on feedback from early adopters). Anyway, soon after being able to run pretty much as much of the Raku language as any other backend, I started on the dynamic optimizer. It gathered type statistics as the program was interpreted, identified hot code, put it into &lt;a href="https://en.wikipedia.org/wiki/Static_single_assignment_form"&gt;SSA form&lt;/a&gt;, used the type statistics to insert guards, used those together with static properties of the bytecode to analyze and optimize, and produced &lt;em&gt;specialized bytecode&lt;/em&gt; for the function in question. This bytecode could elide type checks and various lookups, as well as using a range of internal ops that make all kinds of assumptions, which were safe because of the program properties that were proved by the optimizer. This is called specialized bytecode because it has had a lot of its genericity &amp;#8211; which would allow it to work correctly on all types of value that we might encounter &amp;#8211; removed, in favor of working in a particular special case that actually occurs at runtime. (Code, especially in more dynamic languages, is generally far more generic in theory than it ever turns out to be in practice.)&lt;/p&gt;



&lt;p&gt;This component &amp;#8211; the specializer, known internally as &amp;#8220;spesh&amp;#8221; &amp;#8211; delivered a significant further improvement in the performance of Raku programs, and with time its sophistication has grown, taking in optimizations such as&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Inline_expansion"&gt;inlining&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Escape_analysis"&gt;escape analysis with scalar replacement&lt;/a&gt;. These aren&amp;#8217;t easy things to build &amp;#8211; but once a runtime has them, they create design possibilities that didn&amp;#8217;t previously exist, and make decisions made in their absence look sub-optimal.&lt;/p&gt;



&lt;p&gt;Of note, those special-cased language-specific mechanisms, baked into the runtime to get some speed in the early days, instead become something of a liability and a bottleneck. They have complex semantics, which means they are either opaque to the optimizer (so it can&amp;#8217;t reason about them, meaning optimization is inhibited) or they need special casing in the optimizer (a liability).&lt;/p&gt;



&lt;p&gt;So, back to specializer plugins. I reached a point where I wanted to take on the performance of things like&amp;nbsp;&lt;code&gt;$obj.?meth&lt;/code&gt;&amp;nbsp;(the &amp;#8220;call me maybe&amp;#8221; dispatch),&amp;nbsp;&lt;code&gt;$obj.SomeType::meth()&lt;/code&gt;&amp;nbsp;(dispatch qualified with a class to start looking in), and private method calls in roles (which can&amp;#8217;t be resolved statically). At the same time, I was getting ready to implement some amount of escape analysis, but realized that it was going to be of very limited utility because assignment had also been special-cased in the VM, with a chunk of opaque C code doing the hot path stuff.&lt;/p&gt;



&lt;p&gt;But why did we have the C code doing that hot-path stuff? Well, because it&amp;#8217;d be too espensive to have every assignment call a VM-level function that does a bunch of checks and logic. Why is that costly? Because of function call overhead and the costs of interpretation. This was all true once upon a time. But, some years of development later:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Inlining was implemented, and could eliminate the overhead of doing a function call&lt;/li&gt;&lt;li&gt;We could compile to machine code, eliminating interpretation overhead&lt;/li&gt;&lt;li&gt;We were in a position where we had type information to hand in the specializer that would let us eliminate branches in the C code, but since it was just an opaque function we called, there was no way to take this opportunity&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;I solved the assignment problem and the dispatch problems mentioned above with the introduction of a single new mechanism: specializer plugins. They work as follows:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;The first time we reach a given callsite in the bytecode, we run the plugin. It produces a code object to invoke, along with a set of guards (conditions that have to be met in order to use that code object result)&lt;/li&gt;&lt;li&gt;The next time we reach it, we check if the guards are met, and if so, just use the result&lt;/li&gt;&lt;li&gt;If not, we run the plugin again, and stack up a guard set at the callsite&lt;/li&gt;&lt;li&gt;We keep statistics on how often a given guard set succeeds, and then use that in the specializer&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;The vast majority of cases are monomorphic, meaning that only one set of guards are produced and they always succeed thereafter. The specializer can thus compile those guards into the specialized bytecode and then assume the given target invocant is what will be invoked. (Further, duplicate guards can be eliminated, so the guards a particular plugin introduces may reduce to zero.)&lt;/p&gt;



&lt;p&gt;Specializer plugins felt pretty great. One new mechanism solved multiple optimization headaches.&lt;/p&gt;



&lt;p&gt;The new MoarVM dispatch mechanism is the answer to a fairly simple question: what if we get rid of&amp;nbsp;&lt;em&gt;all&lt;/em&gt;&amp;nbsp;the dispatch-related special-case mechanisms in favor of something a bit like specializer plugins? The resulting mechanism would need to be a more powerful than specializer plugins. Further, I could learn from some of the shortcomings of specializer plugins. Thus, while they will go away after a relatively short lifetime, I think it&amp;#8217;s fair to say that I would not have been in a place to design the new MoarVM dispatch mechanism without that experience.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#the-dispatch-op-and-the-bootstrap-dispatchers"&gt;&lt;/a&gt;The dispatch op and the bootstrap dispatchers&lt;/h3&gt;



&lt;p&gt;All the method caching. All the multi dispatch caching. All the specializer plugins. All the invocation protocol stuff for unwrapping the bytecode handle in a code object. It&amp;#8217;s all going away, in favor of a single new dispatch instruction. Its name is, boringly enough,&amp;nbsp;&lt;code&gt;dispatch&lt;/code&gt;. It looks like this:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
dispatch_o result, 'dispatcher-name', callsite, arg0, arg1, ..., argN

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Which means:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Use the dispatcher called&amp;nbsp;&lt;code&gt;dispatcher-name&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Give it the argument registers specified (the callsite referenced indicates the number of arguments)&lt;/li&gt;&lt;li&gt;Put the object result of the dispatch into the register&amp;nbsp;&lt;code&gt;result&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;(Aside: this implies a new calling convention, whereby we no longer copy the arguments into an argument buffer, but instead pass the base of the register set and a pointer into the bytecode where the register argument map is found, and then do a lookup&amp;nbsp;&lt;code&gt;registers[map[argument_index]]&lt;/code&gt;&amp;nbsp;to get the value for an argument. That alone is a saving when we interpret, because we no longer need a loop around the interpreter per argument.)&lt;/p&gt;



&lt;p&gt;Some of the arguments might be things we&amp;#8217;d traditionally call arguments. Some are aimed at the dispatch process itself. It doesn&amp;#8217;t really matter &amp;#8211; but it&amp;nbsp;&lt;em&gt;is&lt;/em&gt;&amp;nbsp;more optimal if we arrange to put arguments that are only for the dispatch first (for example, the method name), and those for the target of the dispatch afterwards (for example, the method parameters).&lt;/p&gt;



&lt;p&gt;The new bootstrap mechanism provides a small number of built-in dispatchers, whose names start with &amp;#8220;boot-&amp;#8220;. They are:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;code&gt;boot-value&lt;/code&gt;&amp;#8211; take the first argument and use it as the result (the identity function, except discarding any further arguments)&lt;/li&gt;&lt;li&gt;&lt;code&gt;boot-constant&lt;/code&gt;&amp;nbsp;&amp;#8211; take the first argument and produce it as the result, but also treat it as a constant value that will always be produced (thus meaning the optimizer could consider any pure code used to calculate the value as dead)&lt;/li&gt;&lt;li&gt;&lt;code&gt;boot-code&lt;/code&gt;&amp;nbsp;&amp;#8211; take the first argument, which must be a VM bytecode handle, and run that bytecode, passing the rest of the arguments as its parameters; evaluate to the return value of the bytecode&lt;/li&gt;&lt;li&gt;&lt;code&gt;boot-syscall&lt;/code&gt;&amp;nbsp;&amp;#8211; treat the first argument as the name of a VM-provided built-in operation, and call it, providing the remaining arguments as its parameters&lt;/li&gt;&lt;li&gt;&lt;code&gt;boot-resume&lt;/code&gt;&amp;nbsp;&amp;#8211; resume the topmost ongoing dispatch&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;That&amp;#8217;s pretty much it. Every dispatcher we build, to teach the runtime about some other kind of dispatch behavior, eventually terminates in one of these.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#building-on-the-bootstrap"&gt;&lt;/a&gt;Building on the bootstrap&lt;/h3&gt;



&lt;p&gt;Teaching MoarVM about different kinds of dispatch is done using nothing less than the dispatch mechanism itself! For the most part,&amp;nbsp;&lt;code&gt;boot-syscall&lt;/code&gt;&amp;nbsp;is used in order to register a dispatcher, set up the guards, and provide the result that goes with them.&lt;/p&gt;



&lt;p&gt;Here is a minimal example, taken from the dispatcher test suite, showing how a dispatcher that provides the identity function would look:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
nqp::dispatch('boot-syscall', 'dispatcher-register', 'identity', -&amp;gt; $capture {
    nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'boot-value', $capture);
});
sub identity($x) {
    nqp::dispatch('identity', $x)
}
ok(identity(42) == 42, 'Can define identity dispatch (1)');
ok(identity('foo') eq 'foo', 'Can define identity dispatch (2)');

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In the first statement, we call the&amp;nbsp;&lt;code&gt;dispatcher-register&lt;/code&gt;&amp;nbsp;MoarVM system call, passing a name for the dispatcher along with a closure, which will be called each time we need to handle the dispatch (which I tend to refer to as the &amp;#8220;dispatch callback&amp;#8221;). It receives a single argument, which is a capture of arguments (not actually a Raku-level&amp;nbsp;&lt;code&gt;Capture&lt;/code&gt;, but the idea &amp;#8211; an object containing a set of call arguments &amp;#8211; is the same).&lt;/p&gt;



&lt;p&gt;Every user-defined dispatcher should eventually use&amp;nbsp;&lt;code&gt;dispatcher-delegate&lt;/code&gt;&amp;nbsp;in order to identify another dispatcher to pass control along to. In this case, it delegates immediately to&amp;nbsp;&lt;code&gt;boot-value&lt;/code&gt;&amp;nbsp;&amp;#8211; meaning it really is nothing except a wrapper around the&amp;nbsp;&lt;code&gt;boot-value&lt;/code&gt;&amp;nbsp;built-in dispatcher.&lt;/p&gt;



&lt;p&gt;The sub&amp;nbsp;&lt;code&gt;identity&lt;/code&gt;&amp;nbsp;contains a single static occurrence of the&amp;nbsp;&lt;code&gt;dispatch&lt;/code&gt;&amp;nbsp;op. Given we call the sub twice, we will encounter this op twice at runtime, but the two times are very different.&lt;/p&gt;



&lt;p&gt;The first time is the &amp;#8220;record&amp;#8221; phase. The arguments are formed into a capture and the callback runs, which in turn passes it along to the&amp;nbsp;&lt;code&gt;boot-value&lt;/code&gt;&amp;nbsp;dispatcher, which produces the result. This results in an extremely simple dispatch program, which says that the result should be the first argument in the capture. Since there&amp;#8217;s no guards, this will always be a valid result.&lt;/p&gt;



&lt;p&gt;The second time we encounter the&amp;nbsp;&lt;code&gt;dispatch&lt;/code&gt;&amp;nbsp;op, it already has a dispatch program recorded there, so we are in run mode. Turning on a debugging mode in the MoarVM source, we can see the dispatch program that results looks like this:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
Dispatch program (1 temporaries)
  Ops:
    Load argument 0 into temporary 0
    Set result object value from temporary 0

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That is, it reads argument 0 into a temporary location and then sets that as the result of the dispatch. Notice how there is no mention of the fact that we went through an extra layer of dispatch; those have zero cost in the resulting dispatch program.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#capture-manipulation"&gt;&lt;/a&gt;Capture manipulation&lt;/h3&gt;



&lt;p&gt;Argument captures are immutable. Various VM syscalls exist to transform them into new argument captures with some tweak, for example dropping or inserting arguments. Here&amp;#8217;s a further example from the test suite:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
nqp::dispatch('boot-syscall', 'dispatcher-register', 'drop-first', -&amp;gt; $capture {
    my $capture-derived := nqp::dispatch('boot-syscall', 'dispatcher-drop-arg', $capture, 0);
    nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'boot-value', $capture-derived);
});
ok(nqp::dispatch('drop-first', 'first', 'second') eq 'second',
    'dispatcher-drop-arg works');

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This drops the first argument before passing the capture on to the&amp;nbsp;&lt;code&gt;boot-value&lt;/code&gt;&amp;nbsp;dispatcher &amp;#8211; meaning that it will return the second argument. Glance back at the previous dispatch program for the identity function. Can you guess how this one will look?&lt;/p&gt;



&lt;p&gt;Well, here it is:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
Dispatch program (1 temporaries)
  Ops:
    Load argument 1 into temporary 0
    Set result string value from temporary 0

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again, while in the record phase of such a dispatcher we really do create capture objects and make a dispatcher delegation, the resulting dispatch program is far simpler.&lt;/p&gt;



&lt;p&gt;Here&amp;#8217;s a slightly more involved example:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
my $target := -&amp;gt; $x { $x + 1 }
nqp::dispatch('boot-syscall', 'dispatcher-register', 'call-on-target', -&amp;gt; $capture {
    my $capture-derived := nqp::dispatch('boot-syscall',
            'dispatcher-insert-arg-literal-obj', $capture, 0, $target);
    nqp::dispatch('boot-syscall', 'dispatcher-delegate',
            'boot-code-constant', $capture-derived);
});
sub cot() { nqp::dispatch('call-on-target', 49) }
ok(cot() == 50,
    'dispatcher-insert-arg-literal-obj works at start of capture');
ok(cot() == 50,
    'dispatcher-insert-arg-literal-obj works at start of capture after link too');

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here, we have a closure stored in a variable&amp;nbsp;&lt;code&gt;$target&lt;/code&gt;. We insert it as the first argument of the capture, and then delegate to&amp;nbsp;&lt;code&gt;boot-code-constant&lt;/code&gt;, which will invoke that code object and pass the other dispatch arguments to it. Once again, at the record phase, we really do something like:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Create a new capture with a code object inserted at the start&lt;/li&gt;&lt;li&gt;Delegate to the boot code constant dispatcher, which&amp;#8230;&lt;/li&gt;&lt;li&gt;&amp;#8230;creates a new capture without the original argument and runs bytecode with those arguments&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;And the resulting dispatch program? It&amp;#8217;s this:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
Dispatch program (1 temporaries)
  Ops:
    Load collectable constant at index 0 into temporary 0
    Skip first 0 args of incoming capture; callsite from 0
    Invoke MVMCode in temporary 0

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That is, load the constant bytecode handle that we&amp;#8217;re going to invoke, set up the args (which are in this case equal to those of the incoming capture), and then invoke the bytecode with those arguments. The argument shuffling is, once again, gone. In general, whenever the arguments we do an eventual bytecode invocation with are a tail of the initial dispatch arguments, the arguments transform becomes no more than a pointer addition.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#guards"&gt;&lt;/a&gt;Guards&lt;/h3&gt;



&lt;p&gt;All of the dispatch programs seen so far have been unconditional: once recorded at a given callsite, they shall always be used. The big missing piece to make such a mechanism have practical utility is guards. Guards assert properties such as the type of an argument or if the argument is definite (&lt;code&gt;Int:D&lt;/code&gt;) or not (&lt;code&gt;Int:U&lt;/code&gt;).&lt;/p&gt;



&lt;p&gt;Here&amp;#8217;s a somewhat longer test case, with some explanations placed throughout it.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# A couple of classes for test purposes
my class C1 { }
my class C2 { }

# A counter used to make sure we're only invokving the dispatch callback as
# many times as we expect.
my $count := 0;

# A type-name dispatcher that maps a type into a constant string value that
# is its name. This isn't terribly useful, but it is a decent small example.
nqp::dispatch('boot-syscall', 'dispatcher-register', 'type-name', -&amp;gt; $capture {
    # Bump the counter, just for testing purposes.
    $count++;

    # Obtain the value of the argument from the capture (using an existing
    # MoarVM op, though in the future this may go away in place of a syscall)
    # and then obtain the string typename also.
    my $arg-val := nqp::captureposarg($capture, 0);
    my str $name := $arg-val.HOW.name($arg-val);

    # This outcome is only going to be valid for a particular type. We track
    # the argument (which gives us an object back that we can use to guard
    # it) and then add the type guard.
    my $arg := nqp::dispatch('boot-syscall', 'dispatcher-track-arg', $capture, 0);
    nqp::dispatch('boot-syscall', 'dispatcher-guard-type', $arg);

    # Finally, insert the type name at the start of the capture and then
    # delegate to the boot-constant dispatcher.
    nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'boot-constant',
        nqp::dispatch('boot-syscall', 'dispatcher-insert-arg-literal-str',
            $capture, 0, $name));
});

# A use of the dispatch for the tests. Put into a sub so there's a single
# static dispatch op, which all dispatch programs will hang off.
sub type-name($obj) {
    nqp::dispatch('type-name', $obj)
}

# Check with the first type, making sure the guard matches when it should
# (although this test would pass if the guard were ignored too).
ok(type-name(C1) eq 'C1', 'Dispatcher setting guard works');
ok($count == 1, 'Dispatch callback ran once');
ok(type-name(C1) eq 'C1', 'Can use it another time with the same type');
ok($count == 1, 'Dispatch callback was not run again');

# Test it with a second type, both record and run modes. This ensures the
# guard really is being checked.
ok(type-name(C2) eq 'C2', 'Can handle polymorphic sites when guard fails');
ok($count == 2, 'Dispatch callback ran a second time for new type');
ok(type-name(C2) eq 'C2', 'Second call with new type works');

# Check that we can use it with the original type too, and it has stacked
# the dispatch programs up at the same callsite.
ok(type-name(C1) eq 'C1', 'Call with original type still works');
ok($count == 2, 'Dispatch callback only ran a total of 2 times');

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This time two dispatch programs get produced, one for&amp;nbsp;&lt;code&gt;C1&lt;/code&gt;:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
Dispatch program (1 temporaries)
  Ops:
    Guard arg 0 (type=C1)
    Load collectable constant at index 1 into temporary 0
    Set result string value from temporary 0

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And another for C2:&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
Dispatch program (1 temporaries)
  Ops:
    Guard arg 0 (type=C2)
    Load collectable constant at index 1 into temporary 0
    Set result string value from temporary 0

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Once again, no leftovers from capture manipulation, tracking, or dispatcher delegation; the dispatch program does a type guard against an argument, then produces the result string. The whole call to&amp;nbsp;&lt;code&gt;$arg-val.HOW.name($arg-val)&lt;/code&gt;&amp;nbsp;is elided, the dispatcher we wrote encoding the knowledge &amp;#8211; in a way that the VM can understand &amp;#8211; that a type&amp;#8217;s name can be considered immutable.&lt;/p&gt;



&lt;p&gt;This example is a bit contrived, but now consider that we instead look up a method and guard on the invocant type: that&amp;#8217;s a method cache! Guard the types of more of the arguments, and we have a multi cache! Do both, and we have a multi-method cache.&lt;/p&gt;



&lt;p&gt;The latter is interesting in so far as both the method dispatch&amp;nbsp;&lt;em&gt;and&lt;/em&gt;&amp;nbsp;the multi dispatch want to guard on the invocant. In fact, in MoarVM today there will be two such type tests until we get to the point where the specializer does its work and eliminates these duplicated guards. However, the new dispatcher does not treat the&amp;nbsp;&lt;code&gt;dispatcher-guard-type&lt;/code&gt;&amp;nbsp;as a kind of imperative operation that writes a guard into the resultant dispatch program. Instead, it declares that the argument in question must be guarded. If some other dispatcher already did that, it&amp;#8217;s idempotent. The guards are emitted once all dispatch programs we delegate through, on the path to a final outcome, have had their say.&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Fun aside:&lt;/em&gt;&amp;nbsp;those being especially attentive will have noticed that the dispatch mechanism is used as part of implementing new dispatchers too, and indeed, this ultimately will mean that the specializer can specialize the dispatchers and have them JIT-compiled into something more efficient too. After all, from the perspective of MoarVM, it&amp;#8217;s all just bytecode to run; it&amp;#8217;s just that some of it is bytecode that tells the VM how to execute Raku programs more efficiently!&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#dispatch-resumption"&gt;&lt;/a&gt;Dispatch resumption&lt;/h3&gt;



&lt;p&gt;A resumable dispatcher needs to do two things:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;Provide a resume callback as well as a dispatch one when registering the dispatcher&lt;/li&gt;&lt;li&gt;In the dispatch callback, specify a capture, which will form the resume initialization state&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;When a resumption happens, the resume callback will be called, with any arguments for the resumption. It can also obtain the resume initialization state that was set in the dispatch callback. The resume initialization state contains the things needed in order to continue with the dispatch &lt;em&gt;the first time it is resumed&lt;/em&gt;. We&amp;#8217;ll take a look at how this works for method dispatch to see a concrete example. I&amp;#8217;ll also, at this point, switch to looking at the real Rakudo dispatchers, rather than simplified test cases.&lt;/p&gt;



&lt;p&gt;The Rakudo dispatchers take advantage of delegation, duplicate guards, and capture manipulations all having no runtime cost in the resulting dispatch program to, in my mind at least, quite nicely factor what is a somewhat involved dispatch process. There are multiple entry points to method dispatch: the normal boring&amp;nbsp;&lt;code&gt;$obj.meth()&lt;/code&gt;, the qualified&amp;nbsp;&lt;code&gt;$obj.Type::meth()&lt;/code&gt;, and the call me maybe&amp;nbsp;&lt;code&gt;$obj.?meth()&lt;/code&gt;. These have common resumption semantics &amp;#8211; or at least, they can be made to provided we always carry a starting type in the resume initialization state, which is the type of the object that we do the method dispatch on.&lt;/p&gt;



&lt;p&gt;Here is the entry point to dispatch for a normal method dispatch, with the boring details of reporting missing method errors stripped out.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# A standard method call of the form $obj.meth($arg); also used for the
# indirect form $obj."$name"($arg). It receives the decontainerized invocant,
# the method name, and the the args (starting with the invocant including any
# container).
nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-meth-call', -&amp;gt; $capture {
    # Try to resolve the method call using the MOP.
    my $obj := nqp::captureposarg($capture, 0);
    my str $name := nqp::captureposarg_s($capture, 1);
    my $meth := $obj.HOW.find_method($obj, $name);

    # Report an error if there is no such method.
    unless nqp::isconcrete($meth) {
        !!! 'Error reporting logic elided for brevity';
    }

    # Establish a guard on the invocant type and method name (however the name
    # may well be a literal, in which case this is free).
    nqp::dispatch('boot-syscall', 'dispatcher-guard-type',
        nqp::dispatch('boot-syscall', 'dispatcher-track-arg', $capture, 0));
    nqp::dispatch('boot-syscall', 'dispatcher-guard-literal',
        nqp::dispatch('boot-syscall', 'dispatcher-track-arg', $capture, 1));

    # Add the resolved method and delegate to the resolved method dispatcher.
    my $capture-delegate := nqp::dispatch('boot-syscall',
        'dispatcher-insert-arg-literal-obj', $capture, 0, $meth);
    nqp::dispatch('boot-syscall', 'dispatcher-delegate',
        'raku-meth-call-resolved', $capture-delegate);
});

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now for the resolved method dispatcher, which is where the resumption is handled. First, let&amp;#8217;s look at the normal dispatch callback (the resumption callback is included but empty; I&amp;#8217;ll show it a little later).&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# Resolved method call dispatcher. This is used to call a method, once we have
# already resolved it to a callee. Its first arg is the callee, the second and
# third are the type and name (used in deferral), and the rest are the args to
# the method.
nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-meth-call-resolved',
    # Initial dispatch
    -&amp;gt; $capture {
        # Save dispatch state for resumption. We don't need the method that will
        # be called now, so drop it.
        my $resume-capture := nqp::dispatch('boot-syscall', 'dispatcher-drop-arg',
            $capture, 0);
        nqp::dispatch('boot-syscall', 'dispatcher-set-resume-init-args', $resume-capture);

        # Drop the dispatch start type and name, and delegate to multi-dispatch or
        # just invoke if it's single dispatch.
        my $delegate_capture := nqp::dispatch('boot-syscall', 'dispatcher-drop-arg',
            nqp::dispatch('boot-syscall', 'dispatcher-drop-arg', $capture, 1), 1);
        my $method := nqp::captureposarg($delegate_capture, 0);
        if nqp::istype($method, Routine) &amp;amp;&amp;amp; $method.is_dispatcher {
            nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi', $delegate_capture);
        }
        else {
            nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke', $delegate_capture);
        }
    },
    # Resumption
    -&amp;gt; $capture {
        ... 'Will be shown later';
    });

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;There&amp;#8217;s an arguable cheat in&amp;nbsp;&lt;code&gt;raku-meth-call&lt;/code&gt;: it doesn&amp;#8217;t actually insert the type object of the invocant in place of the invocant. It turns out that it doesn&amp;#8217;t really matter. Otherwise, I think the comments (which are to be found in the real implementation also) tell the story pretty well.&lt;/p&gt;



&lt;p&gt;One important point that may not be clear &amp;#8211; but follows a repeating theme &amp;#8211; is that the setting of the resume initialization state is also more of a declarative rather than an imperative thing: there isn&amp;#8217;t a runtime cost at the time of the dispatch, but rather we keep enough information around in order to be able to reconstruct the resume initialization state at the point we need it. (In fact, when we are in the run phase of a resume, we don&amp;#8217;t even have to reconstruct it in the sense of creating a capture object.)&lt;/p&gt;



&lt;p&gt;Now for the resumption. I&amp;#8217;m going to present a heavily stripped down version that only deals with the&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;semantics (the full thing has to deal with such delights as&amp;nbsp;&lt;code&gt;lastcall&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;nextcallee&lt;/code&gt;&amp;nbsp;too). The resume initialization state exists to seed the resumption process. Once we know we actually do have to deal with resumption, we can do things like calculating the full list of methods in the inheritance graph that we want to walk through. Each resumable dispatcher gets a single storage slot on the call stack that it can use for its state. It can initialize this in the first step of resumption, and then update it as we go. Or more precisely, it can set up a dispatch program that will do this when run.&lt;/p&gt;



&lt;p&gt;A linked list turns out to be a very convenient data structure for the chain of candidates we will walk through. We can work our way through a linked list by keeping track of the current node, meaning that there need only be a single thing that mutates, which is the current state of the dispatch. The dispatch program mechanism also provides a way to read an attribute from an object, and that is enough to express traversing a linked list into the dispatch program. This also means zero allocations.&lt;/p&gt;



&lt;p&gt;So, without further ado, here is the linked list (rather less pretty in NQP, the restricted Raku subset, than it would be in full Raku):&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
# A linked list is used to model the state of a dispatch that is deferring
# through a set of methods, multi candidates, or wrappers. The Exhausted class
# is used as a sentinel for the end of the chain. The current state of the
# dispatch points into the linked list at the appropriate point; the chain
# itself is immutable, and shared over (runtime) dispatches.
my class DeferralChain {
    has $!code;
    has $!next;
    method new($code, $next) {
        my $obj := nqp::create(self);
        nqp::bindattr($obj, DeferralChain, '$!code', $code);
        nqp::bindattr($obj, DeferralChain, '$!next', $next);
        $obj
    }
    method code() { $!code }
    method next() { $!next }
};
my class Exhausted {};

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And finally, the resumption handling.&lt;/p&gt;


&lt;div class="wp-block-syntaxhighlighter-code "&gt;&lt;pre class="brush: plain; title: ; notranslate"&gt;
nqp::dispatch('boot-syscall', 'dispatcher-register', 'raku-meth-call-resolved',
    # Initial dispatch
    -&amp;gt; $capture {
        ... 'Presented earlier;
    },
    # Resumption. The resume init capture's first two arguments are the type
    # that we initially did a method dispatch against and the method name
    # respectively.
    -&amp;gt; $capture {
        # Work out the next method to call, if any. This depends on if we have
        # an existing dispatch state (that is, a method deferral is already in
        # progress).
        my $init := nqp::dispatch('boot-syscall', 'dispatcher-get-resume-init-args');
        my $state := nqp::dispatch('boot-syscall', 'dispatcher-get-resume-state');
        my $next_method;
        if nqp::isnull($state) {
            # No state, so just starting the resumption. Guard on the
            # invocant type and name.
            my $track_start_type := nqp::dispatch('boot-syscall', 'dispatcher-track-arg', $init, 0);
            nqp::dispatch('boot-syscall', 'dispatcher-guard-type', $track_start_type);
            my $track_name := nqp::dispatch('boot-syscall', 'dispatcher-track-arg', $init, 1);
            nqp::dispatch('boot-syscall', 'dispatcher-guard-literal', $track_name);

            # Also guard on there being no dispatch state.
            my $track_state := nqp::dispatch('boot-syscall', 'dispatcher-track-resume-state');
            nqp::dispatch('boot-syscall', 'dispatcher-guard-literal', $track_state);

            # Build up the list of methods to defer through.
            my $start_type := nqp::captureposarg($init, 0);
            my str $name := nqp::captureposarg_s($init, 1);
            my @mro := nqp::can($start_type.HOW, 'mro_unhidden')
                ?? $start_type.HOW.mro_unhidden($start_type)
                !! $start_type.HOW.mro($start_type);
            my @methods;
            for @mro {
                my %mt := nqp::hllize($_.HOW.method_table($_));
                if nqp::existskey(%mt, $name) {
                    @methods.push(%mt{$name});
                }
            }

            # If there's nothing to defer to, we'll evaluate to Nil (just don't set
            # the next method, and it happens below).
            if nqp::elems(@methods) &amp;gt;= 2 {
                # We can defer. Populate next method.
                @methods.shift; # Discard the first one, which we initially called
                $next_method := @methods.shift; # The immediate next one

                # Build chain of further methods and set it as the state.
                my $chain := Exhausted;
                while @methods {
                    $chain := DeferralChain.new(@methods.pop, $chain);
                }
                nqp::dispatch('boot-syscall', 'dispatcher-set-resume-state-literal', $chain);
            }
        }
        elsif !nqp::istype($state, Exhausted) {
            # Already working through a chain of method deferrals. Obtain
            # the tracking object for the dispatch state, and guard against
            # the next code object to run.
            my $track_state := nqp::dispatch('boot-syscall', 'dispatcher-track-resume-state');
            my $track_method := nqp::dispatch('boot-syscall', 'dispatcher-track-attr',
                $track_state, DeferralChain, '$!code');
            nqp::dispatch('boot-syscall', 'dispatcher-guard-literal', $track_method);

            # Update dispatch state to point to next method.
            my $track_next := nqp::dispatch('boot-syscall', 'dispatcher-track-attr',
                $track_state, DeferralChain, '$!next');
            nqp::dispatch('boot-syscall', 'dispatcher-set-resume-state', $track_next);

            # Set next method, which we shall defer to.
            $next_method := $state.code;
        }
        else {
            # Dispatch already exhausted; guard on that and fall through to returning
            # Nil.
            my $track_state := nqp::dispatch('boot-syscall', 'dispatcher-track-resume-state');
            nqp::dispatch('boot-syscall', 'dispatcher-guard-literal', $track_state);
        }

        # If we found a next method...
        if nqp::isconcrete($next_method) {
            # Call with same (that is, original) arguments. Invoke with those.
            # We drop the first two arguments (which are only there for the
            # resumption), add the code object to invoke, and then leave it
            # to the invoke or multi dispatcher.
            my $just_args := nqp::dispatch('boot-syscall', 'dispatcher-drop-arg',
                nqp::dispatch('boot-syscall', 'dispatcher-drop-arg', $init, 0),
                0);
            my $delegate_capture := nqp::dispatch('boot-syscall',
                'dispatcher-insert-arg-literal-obj', $just_args, 0, $next_method);
            if nqp::istype($next_method, Routine) &amp;amp;&amp;amp; $next_method.is_dispatcher {
                nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-multi',
                        $delegate_capture);
            }
            else {
                nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'raku-invoke',
                        $delegate_capture);
            }
        }
        else {
            # No method, so evaluate to Nil (boot-constant disregards all but
            # the first argument).
            nqp::dispatch('boot-syscall', 'dispatcher-delegate', 'boot-constant',
                nqp::dispatch('boot-syscall', 'dispatcher-insert-arg-literal-obj',
                    $capture, 0, Nil));
        }
    });

&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That&amp;#8217;s quite a bit to take in, and quite a bit of code. Remember, however, that this is only run for the record phase of a dispatch resumption. It also produces a dispatch program at the callsite of the&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;, with the usual guards and outcome. Implicit guards are created for the dispatcher that we are resuming at that point. In the most common case this will end up monomorphic or bimorphic, although situations involving nestings of multiple dispatch or method dispatch could produce a more morphic callsite.&lt;/p&gt;



&lt;p&gt;The design I&amp;#8217;ve picked forces resume callbacks to deal with two situations: the first resumption and the latter resumptions. This is not ideal in a couple of ways:&lt;/p&gt;



&lt;ol class="wp-block-list"&gt;&lt;li&gt;It&amp;#8217;s a bit inconvenient for those writing dispatch resume callbacks. However, it&amp;#8217;s not like this is a particularly common activity!&lt;/li&gt;&lt;li&gt;The difference results in two dispatch programs being stacked up at a callsite that might otherwise get just one&lt;/li&gt;&lt;/ol&gt;



&lt;p&gt;Only the second of these really matters. The reason for the non-uniformity is to make sure that the overwhelming majority of calls, which never lead to a dispatch resumption, incur no per-dispatch cost for a feature that they never end up using. If the result is a little more cost for those using the feature, so be it. In fact, early benchmarking shows&amp;nbsp;&lt;code&gt;callsame&lt;/code&gt;&amp;nbsp;with&amp;nbsp;&lt;code&gt;wrap&lt;/code&gt;&amp;nbsp;and method calls seems to be up to 10 times faster using the new dispatcher than in current Rakudo, and that&amp;#8217;s&amp;nbsp;&lt;em&gt;before&lt;/em&gt;&amp;nbsp;the specializer understands enough about it to improve things further!&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#whats-done-so-far"&gt;&lt;/a&gt;What&amp;#8217;s done so far&lt;/h3&gt;



&lt;p&gt;Everything I&amp;#8217;ve discussed above is implemented, except that I may have given the impression somewhere that multiple dispatch is fully implemented using the new dispatcher, and that is not the case yet (no handling of&amp;nbsp;&lt;code&gt;where&lt;/code&gt;&amp;nbsp;clauses and no dispatch resumption support).&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#next-steps"&gt;&lt;/a&gt;Next steps&lt;/h3&gt;



&lt;p&gt;Getting the missing bits of multiple dispatch fully implemented is the obvious next step. The other missing semantic piece is support for&amp;nbsp;&lt;code&gt;callwith&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;nextwith&lt;/code&gt;, where we wish to change the arguments that are being used when moving to the next candidate. A few other minor bits aside, that in theory will get all of the Raku dispatch semantics at least supported.&lt;/p&gt;



&lt;p&gt;Currently, all standard method calls (&lt;code&gt;$obj.meth()&lt;/code&gt;) and other calls (&lt;code&gt;foo()&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;$foo()&lt;/code&gt;) go via the existing dispatch mechanism, not the new dispatcher. Those will need to be migrated to use the new dispatcher also, and any bugs that are uncovered will need fixing. That will get things to the point where the new dispatcher is&amp;nbsp;&lt;em&gt;semantically ready&lt;/em&gt;.&lt;/p&gt;



&lt;p&gt;After that comes performance work: making sure that the specializer is able to deal with dispatch program guards and outcomes. The goal, initially, is to get steady state performance of common calling forms to perform at least as well as in the current&amp;nbsp;&lt;code&gt;master&lt;/code&gt;&amp;nbsp;branch of Rakudo. It&amp;#8217;s already clear enough there will be some big wins for some things that to date have been glacial, but it should not come at the cost of regression on the most common kinds of dispatch, which have received plenty of optimization effort before now.&lt;/p&gt;



&lt;p&gt;Furthermore, NQP &amp;#8211; the restricted form of Raku that the Rakudo compiler and other bits of the runtime guts are written in &amp;#8211; also needs to be migrated to use the new dispatcher. Only when that is done will it be possible to rip out the current method cache, multiple dispatch cache, and so forth from MoarVM.&lt;/p&gt;



&lt;p&gt;An open question is how to deal with backends other than MoarVM. Ideally, the new dispatch mechanism will be ported to those. A decent amount of it should be possible to express in terms of the JVM&amp;#8217;s &lt;code&gt;invokedynamic&lt;/code&gt; (and this would all probably play quite well with a Truffle-based Raku implementation, although I&amp;#8217;m not sure there is a current active effort in that area).&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#future-opportunities"&gt;&lt;/a&gt;Future opportunities&lt;/h3&gt;



&lt;p&gt;While my current focus is to ship a Rakudo and MoarVM release that uses the new dispatcher mechanism, that won&amp;#8217;t be the end of the journey. Some immediate ideas:&lt;/p&gt;



&lt;ul class="wp-block-list"&gt;&lt;li&gt;Method calls on roles need to pun the role into a class, and so method lookup returns a closure that does that and replaces the invocant. That&amp;#8217;s a lot of indirection; the new dispatcher could obtain the pun and produce a dispatch program that replaces the role type object with the punned class type object, which would make the per-call cost far lower.&lt;/li&gt;&lt;li&gt;I expect both the&amp;nbsp;&lt;code&gt;handles&lt;/code&gt;&amp;nbsp;(delegation) and&amp;nbsp;&lt;code&gt;FALLBACK&lt;/code&gt;&amp;nbsp;(handling missing method call) mechanisms can be made to perform better using the new dispatcher&lt;/li&gt;&lt;li&gt;The current implementation of&amp;nbsp;&lt;code&gt;assuming&lt;/code&gt;&amp;nbsp;&amp;#8211; used to curry or otherwise prime arguments for a routine &amp;#8211; is not ideal, and an implementation that takes advantage of the argument rewriting capabilities of the new dispatcher would likely perform a great deal better&lt;/li&gt;&lt;/ul&gt;



&lt;p&gt;Some new language features may also be possible to provide in an efficient way with the help of the new dispatch mechanism. For example, there&amp;#8217;s currently not a reliable way to try to invoke a piece of code, just run it if the signature binds, or to do something else if it doesn&amp;#8217;t. Instead, things like the Cro router have to first do a trial bind of the signature, and then do the invoke, which makes routing rather more costly. There&amp;#8217;s also the long suggested idea of providing pattern matching via signatures with the&amp;nbsp;&lt;code&gt;when&lt;/code&gt;&amp;nbsp;construct (for example,&amp;nbsp;&lt;code&gt;when * -&amp;gt; ($x) {}; when * -&amp;gt; ($x, *@tail) { }&lt;/code&gt;), which is pretty much the same need, just in a less dynamic setting.&lt;/p&gt;



&lt;h3 class="wp-block-heading"&gt;&lt;a href="https://gist.github.com/jnthn/157fd5bd91a45cf6e62ecf0b9099bfba#in-closing"&gt;&lt;/a&gt;In closing&amp;#8230;&lt;/h3&gt;



&lt;p&gt;Working on the new dispatch mechanism has been a longer journey than I first expected. The resumption part of the design was especially challenging, and there&amp;#8217;s still a few important details to attend to there. Something like four potential approaches were discarded along the way (although elements of all of them influenced what I&amp;#8217;ve described in this post). Abstractions that hold up are really, really, hard.&lt;/p&gt;



&lt;p&gt;I also ended up having to take a couple of months away from doing Raku work at all, felt a bit crushed during some others, and have been juggling this with the equally important RakuAST project (which will be simplified by being able to assume the presence of the new dispatcher, and also offers me a range of softer Raku hacking tasks, whereas the dispatcher work offers few easy pickings).&lt;/p&gt;



&lt;p&gt;Given all that, I&amp;#8217;m glad to finally be seeing the light at the end of the tunnel. The work that remains is enumerable, and the day we ship a Rakudo and MoarVM release using the new dispatcher feels a small number of months away (and I hope writing that is not tempting fate!)&lt;/p&gt;



&lt;p&gt;The new dispatcher is probably the most significant change to MoarVM since I founded it, in so far as it sees us removing a bunch of things that have been there pretty much since the start. RakuAST will also deliver the greatest architectural change to the Rakudo compiler in a decade. Both are an opportunity to fold years of learning things the hard way into the runtime and compiler. I hope when I look back at it all in another decade&amp;#8217;s time, I&amp;#8217;ll at least feel I made more interesting mistakes this time around.&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">My goodness, it appears I’m writing my first Raku internals blog post in over two years. Of course, two years ago it wasn’t even called Raku. Anyway, without further ado, let’s get on with this shared brainache. What is dispatch? … <a href="https://6guts.wordpress.com/2021/03/15/towards-a-new-general-dispatch-mechanism-in-moarvm/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>jnthnwrthngtn</name>
    </author>
    <id>http://6guts.wordpress.com/?p=583</id>
    <published>2021-03-15T02:08:42Z</published>
    <updated>2021-03-15T02:08:42Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-7864497598813874355.post-3870039225138777138</id>
    <published>2021-03-14T14:33:00.000-07:00</published>
    <updated>2021-03-14T14:33:31.042-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="raku"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="scripting"/>
    <title type="text">Why bother with Scripting?</title>
    <content type="html">&lt;p&gt;Many years back, Larry Wall shared his &lt;a href="https://www.perl.com/pub/2007/12/06/soto-11.html/" target="_blank"&gt;thesis&lt;/a&gt; on the nature of scripting. Since recently even &lt;a href="https://openjdk.java.net/jeps/330"&gt;Java&lt;/a&gt; gained 'script' support I thought it would be fitting to revisit the topic, and hopefully relevant to the perl and raku language community.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The weakness of Larry's treatment (which, to be fair to the author, I think is more intended to be enlightening than to be complete) is the contrast of &lt;i&gt;scripting&lt;/i&gt; with &lt;i&gt;programming&lt;/i&gt;. This contrast does not permit a clear separation because &lt;i&gt;scripts&lt;/i&gt; are &lt;i&gt;programs&lt;/i&gt;. That is to say, no matter how long or short, scripts are written commands for a machine to execute, and I think that's a pretty decent definition of a program in general.&lt;/p&gt;&lt;p&gt;A more useful contrast - and, I think, the intended one - is between &lt;i&gt;scripts&lt;/i&gt; and &lt;i&gt;other sorts of programs&lt;/i&gt;, because that allows us to compare &lt;i&gt;scripting&lt;/i&gt; (writing scripts) with 'programming' (writing non-script programs). And to do that we need to know what other sorts of programs there are.&lt;/p&gt;&lt;p&gt;The short version of that answer is - systems and applications, and a bunch of other things that aren't really relevant to the working programmer, like (embedded) control algorithms, spreadsheets and database queries. (The definition I provided above is very broad, by design, because I don't want to get stuck on boundary questions). Most programmers write applications, some write systems, virtually all write scripts once in a while, though plenty of people who &lt;i&gt;aren't&lt;/i&gt; professional programmers also write scripts.&lt;/p&gt;&lt;p&gt;I think the defining features of applications and systems are, respectively:&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Applications present &lt;i&gt;models&lt;/i&gt; to users (for &lt;i&gt;manipulation&lt;/i&gt;)&lt;/li&gt;&lt;li&gt;Systems provide &lt;i&gt;functionality&lt;/i&gt; to other programs&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Consider for instance a mail client (like thunderbird) in comparison to a mailer daemon (like sendmail) - one provides an interface to read and write e-mails (the model) and the other provides functionality to send that e-mail to other servers.&lt;/p&gt;&lt;p&gt;Note that under this (again, broad) definition, &lt;i&gt;libraries&lt;/i&gt; are also system software, which makes sense, considering that their users are developers (just as for, say, PostgreSQL) who care about things like performance, reliability, and correctness. Incidentally, libraries as well as 'typical' system software (such as database engines and operating system kernels) tend to be written in languages like C and C++ for much the same reasons.&lt;/p&gt;&lt;p&gt;What then, are the differences between scripts, applications, and systems? I think the following is a good list:&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Scripts tend to be short, applications in particular can grow very large.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Scripts tend to be ad-hoc (written for a specific need), applications and systems tend to be designed for a range of use cases. (Very common example: build scripts)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Scripts tend to run only in a specific environment; in contrast, many applications are designed for a range of devices/clients; many systems have specific requirements but the intention is that they can be setup in multiple distinct environments. &lt;br /&gt;&lt;/li&gt;&lt;li&gt;Because scripts are ad-hoc, short, and environment-dependent, many of software engineering standard best practices don't really apply (and are in fact often disregarded).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Obviously these distinctions aren't really binary - 'short' versus 'long', 'ad-hoc' versus 'general purpose'&amp;nbsp; - and can't be used to conclusively settle the question whether something is a script or an application. (If, indeed, that question ever comes up). More important is that for the 10 or so scripts I've written over the past year - some professionally, some not - all or most of these properties held, and I'd be surprised if the same isn't true for most readers.&amp;nbsp;&lt;/p&gt;&lt;p&gt;And - finally coming at the point that I'm trying to make today - these features point to a specific &lt;i&gt;niche&lt;/i&gt; of programs more than to a specific &lt;i&gt;technology&lt;/i&gt; (or set of technologies). To be exact, scripts are (mostly) short, custom programs to automate ad-hoc tasks, tasks that are either to specific or too small to develop and distribute another program for.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This has further implications on the preferred features of a &lt;i&gt;scripting language&lt;/i&gt; (taken to mean, a language designed to enable the development of scripts). In particular:&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;It should make programs concise. The economic rationalization is that the total expected lifetime value of a script, being ad-hoc and context-dependent, is not very great, so writing it should be cheap, which implies that the script should be short).&lt;/li&gt;&lt;li&gt;Related to this, the value provided by type systems is generally less than in larger (application) programs, and the value of extensive modelling features (class hierarchies) is similarly low, so many scripting languages have very weak type systems and data modelling features, if they have them at all.&lt;/li&gt;&lt;li&gt;Interoperation with the environment is on the other hand very important, so I/O features tend to be well-developed. (Contrast C, in which I/O is entirely an afterthought provided by a library).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;It is acceptable to depend on a local environment in implicit ways, since that's what you are going to do anyway.&lt;/li&gt;&lt;li&gt;It is acceptable to &lt;i&gt;warn&lt;/i&gt; on a condition that might've been a fatal error in another programming language.&lt;/li&gt;&lt;li&gt;In fact, I think that concerns of correctness are often different, meaning relaxed, compared to applications, again because scripters don't necessarily expect their scripts to run on every environment and with every possible input. &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;As an example of the last point - Python 3 requires users to be exact about the encoding of their input, causing &lt;i&gt;all sorts&lt;/i&gt; of trouble for unsuspecting scripters when they accidentally try to read ISO-8551 data as UTF-8, or vice versa. Python 2 did not, and for most &lt;i&gt;scripts&lt;/i&gt; - not applications - I actually think that is the right choice.&lt;p&gt;This niche doesn't always exist. In computing environments where everything of interest is adequately captured by an application, or which lacks the ability to effectively automate ad-hoc tasks (I'm thinking in particular of Windows before PowerShell), the practice of scripting tends to not develop. Similarily, in a modern 'cloud' environment, where system setup is controlled by a &lt;a href="https://kubernetes.io/"&gt;state machine&lt;/a&gt; hosted by &lt;a href="https://cloud.google.com/kubernetes-engine" target="_blank"&gt;another organization&lt;/a&gt;, scripting doesn't really have much of a future.&lt;/p&gt;&lt;p&gt;To put it another way, scripting only thrives in an environment that has a lot of 'scriptable' tasks; meaning tasks for which there isn't already a pre-made solution available, environments that have powerful facilities available for a script to access, and whose users are empowered to automate those tasks. Such qualities are common on Unix/Linux 'workstations' but rather less so on smartphones and (as noted before) cloud computing environments.&lt;/p&gt;&lt;p&gt;Truth be told I'm a little worried about that development. I could point to, and expound on, the development and popularity of languages like go and rust, which aren't exactly scripting languages, or the replacement of Javascript with TypeScript, to make the point further, but I don't think that's necessary. At the same time I could point to the development of data science as a discipline to demonstrate that scripting is alive and well (and indeed perhaps more economically relevant than before).&lt;/p&gt;&lt;p&gt;What should be the conclusion for perl 5/7 and raku? I'm not quite sure, mostly because I'm not quite sure whether the broader perl/raku community would prefer their sister languages to be scripting or application languages. (As implied above, I think the Python community chose that they wanted Python 3 to be an application language, and this was not without consequences to their users).&amp;nbsp;&lt;/p&gt;&lt;p&gt;Raku adds a number of features common to application languages (I'm thinking of it's powerful type system in particular), continuing a trend that perl 5 arguably pioneered. This is indeed a very powerful strategy - a language can be introduced for scripts and some of those scripts are then extended into applications (or even systems), thereby ensuring its continued usage. But for it to work, a new&lt;i&gt; &lt;/i&gt;perl family language must be introduced on its &lt;i&gt;scripting&lt;/i&gt; merits, &lt;i&gt;and&lt;/i&gt; there must be a plentiful supply of scriptable tasks to automate, some of which - or a combination of which - grow into an application.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For myself, I would like to see scripting have a bright future. Not just because scripting is the most accessible form of programming, but also because an environment that permits, even requires scripting, is one were not all interesting problems have been solved, one where it's users ask it to do tasks so diverse that there &lt;i&gt;isn't &lt;/i&gt;an app for that, yet. One where the true potential of the wonderful devices that surround is can be explored.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In such a world there might well be a bright future for scripting.&lt;br /&gt;&lt;/p&gt;</content>
    <link rel="replies" type="application/atom+xml" href="http://brrt-to-the-future.blogspot.com/feeds/3870039225138777138/comments/default" title="Reacties posten"/>
    <link rel="replies" type="text/html" href="http://brrt-to-the-future.blogspot.com/2021/03/why-bother-with-scripting.html#comment-form" title="0 reacties"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/3870039225138777138"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/3870039225138777138"/>
    <link rel="alternate" type="text/html" href="http://brrt-to-the-future.blogspot.com/2021/03/why-bother-with-scripting.html" title="Why bother with Scripting?"/>
    <author>
      <name>Bart Wiegmans</name>
      <uri>http://www.blogger.com/profile/05760700924227974153</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry>
    <title>Taking a break from Raku core development</title>
    <link rel="alternate" href="https://6guts.wordpress.com/2020/10/05/taking-a-break-from-raku-core-development/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>I’d like to thank everyone who voted for me in the recent Raku Steering Council elections. By this point, I’ve been working on the language for well over a decade, first to help turn a language design I found fascinating into a working implementation, and since the Christmas release to make that implementation more robust and performant. Overall, it’s been as fun as it has been challenging – in a large part because I’ve found myself sharing the journey with a lot of really great people. I’ve also tried to do my bit to keep the community around the language kind and considerate. Receiving a vote from around 90% of those who participated in the Steering Council elections was humbling.</p>



<p>Alas, I’ve today submitted my resignation to the Steering Council, on personal health grounds. For the same reason, I’ll be taking a step back from Raku core development (Raku, MoarVM, language design, etc.) Please don’t worry too much; I’ll almost certainly be fine. It may be I’m ready to continue working on Raku things in a month or two. It may also be longer. Either way, I think Raku will be better off with a fully sized Steering Council in place, and I’ll be better off without the anxiety that I’m holding a role that I’m not in a place to fulfill.</p>



<h1 class="wp-block-heading"><a href="https://gist.github.com/jnthn/0015f339be0c92c56fdc713852bce0be#steering-council"/></h1>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">I’d like to thank everyone who voted for me in the recent Raku Steering Council elections. By this point, I’ve been working on the language for well over a decade, first to help turn a language design I found fascinating … <a href="https://6guts.wordpress.com/2020/10/05/taking-a-break-from-raku-core-development/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>jnthnwrthngtn</name>
    </author>
    <id>http://6guts.wordpress.com/?p=580</id>
    <published>2020-10-05T19:44:26Z</published>
    <updated>2020-10-05T19:44:26Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-7864497598813874355.post-8209230802915789540</id>
    <published>2019-03-21T15:52:00.001-07:00</published>
    <updated>2019-03-21T15:52:03.295-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="register allocation"/>
    <title type="text">Reverse Linear Scan Allocation is probably a good idea</title>
    <content type="html">Hi hackers! Today First of all, I want to thank everybody who gave such useful &lt;a href="https://news.ycombinator.com/item?id=19425485" target="_blank"&gt;feedback&lt;/a&gt; on my last post.&amp;nbsp; For instance, I found out that the similarity between the expression JIT IR and the Testarossa &lt;a href="https://github.com/eclipse/omr/blob/master/doc/compiler/il/IntroToTrees.md" target="_blank"&gt;Trees IR&lt;/a&gt;&amp;nbsp;is quite remarkable, and that they have a fix for the problem that is quite different from what I had in mind.&lt;br /&gt;
&lt;br /&gt;
Today I want to write something about register allocation, however. Register allocation is probably not my favorite problem, on account of being both messy and thankless. It is a messy problem because - aside from being NP-hard to solve optimally - hardware instruction sets and software ABI's introduce all sorts of annoying constraints. And it is a thankless problem because the case in which a good register allocator is useful - for instance, when there's lots of intermediate values used over a long stretch of code - are fairly rare. Much more common are the cases in which either there are trivially sufficient registers, &lt;i&gt;or &lt;/i&gt;ABI constraints force a spill to memory anyway (e.g. when calling a function, almost all registers can be overwritten).&lt;br /&gt;
&lt;br /&gt;
So, on account of this being not my favorite problem, and also because I promised to implement optimizations in the register allocator, I've been researching if there is a way to do better. And what better place to look than one of the fastest dynamic language implementations arround, &lt;a href="http://luajit.org/luajit.html" target="_blank"&gt;LuaJIT&lt;/a&gt;? So that's what I did, and this post is about what I learned from that.&lt;br /&gt;
&lt;br /&gt;
Truth be told, LuaJIT is not at all a learners' codebase (and I don't think it's author would claim this). It uses a rather terse style of C and lots and lots of preprocessor macros. I had somewhat gotten used to the style from hacking &lt;a href="https://github.com/MoarVM/dynasm/tree/x64-dynamic-registers" target="_blank"&gt;dynasm&lt;/a&gt; though, so that wasn't so bad. What was more surprising is that some of the steps in code generation that are distinct and separate in the MoarVM JIT - instruction selection, register allocation and emitting bytecode - were all blended together in LuaJIT. Over multiple backend architectures, too. And what's more - all these steps were done in &lt;i&gt;reverse order&lt;/i&gt;&amp;nbsp;- from the end of the program (trace) to the beginning. Now that's interesting...&lt;br /&gt;
&lt;br /&gt;
I have no intention of combining all phases of code generation like LuaJIT has. But processing the IR in reverse seems to have some interesting properties. To understand why that is, I'll first have to explain how linear scan allocation currently works in MoarVM, and is most commonly &lt;a href="http://web.cs.ucla.edu/~palsberg/course/cs132/linearscan.pdf" target="_blank"&gt;described&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;First, the &lt;b&gt;live ranges &lt;/b&gt;of program values are computed. Like the name indicates, these represent the range of the program code in which a value is both defined and may be used. Note that for the purpose of register allocation, the notion of a value shifts somewhat. In the expression DAG IR, a value is the result of a single computation. But for the purposes of register allocation, a value includes all its copies, as well as values computed from different conditional branches. This is necessary because when we actually start allocating registers, we need to know when a value is no longer in use (so we can reuse the register) and how long a value will remain in use -&lt;/li&gt;
&lt;li&gt;Because a value may be computed from distinct conditional branches, it is necessary to compute the &lt;b&gt;holes&lt;/b&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;in the live ranges. Holes exists because if a value is defined in both sides of a conditional branch, the range will cover both the earlier (in code order) branch and the later branch - but from the start of the later branch to its definition that value doesn't actually exist. We need this information to prevent the register allocator from trying to spill-and-load a nonexistent value, for instance.&lt;/li&gt;
&lt;li&gt;Only then can we allocate and assign the actual registers to instructions. Because we might have to &lt;b&gt;spill&lt;/b&gt;&lt;b style="font-style: italic;"&gt;&amp;nbsp;&lt;/b&gt;values to memory, and because values now can have multiple definitions, this is a somewhat subtle problem. Also, we'll have to resolve all architecture specific register requirements in this step.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
In the MoarVM register allocator, there's a fourth step and a fifth step. The fourth step exists to ensure that instructions conform to x86 two-operand form (Rather than return the result of an instruction in a third register, x86 reuses one of the input registers as the output register. E.g. all operators are of the form &lt;span style="font-family: Courier New, Courier, monospace;"&gt;a = op(a, b)&lt;/span&gt;&amp;nbsp; rather than &lt;span style="font-family: Courier New, Courier, monospace;"&gt;a = op(b, c)&lt;/span&gt;. This saves on instruction encoding space). The fifth step inserts instructions that are introduced by the third step; this is done so that each instruction has a fixed address in the stream while the stream is being processed.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Altogether this is quite a bit of complexity and work, even for what is arguably the simplest correct global register allocation algorithm. So when I started thinking of the reverse linear scan algorithm employed by LuaJIT, the advantages became clear:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;In LuaJIT, the IR maintains its SSA form - there is only a single definition of a value. This means that when iterating in reverse order, computing the live range becomes trivial. When we first encounter a use of a value, then by definition that is the last use. And when we encounter a definition, that is the only and single definition, and we can release the register.&amp;nbsp; So there's no need to compute the live range in advance of allocation.&lt;/li&gt;
&lt;li&gt;Furthermore, rather than &lt;i&gt;merging&lt;/i&gt;&amp;nbsp;the values of multiple branches into the same live range, each value on either side becomes an individual live range. As a result, the live range of a value never has a hole, further simplifying code.&lt;/li&gt;
&lt;li&gt;LuaJIT uses register &lt;i&gt;hints&lt;/i&gt;&amp;nbsp;to indicate which registers could best be picked for a specific value. This is often determined by how a value is used (e.g., the divisor in a &lt;span style="font-family: Courier New, Courier, monospace;"&gt;div&lt;/span&gt; instruction must be in the &lt;span style="font-family: Courier New, Courier, monospace;"&gt;rcx&lt;/span&gt; register). If the preferred register can't be allocated, the register allocator inserts code to move it to the right place where needed. Having hints can be expected to greatly reduce the need for such code.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
There are downsides as well, of course. Not knowing exactly how long a value will be live while processing it may cause the algorithm to make worse choices in which values to spill. But I don't think that's really a great concern, since figuring out the best possible value is practically impossible anyway, and the most commonly cited heuristic - evict the value that is live furthest in the future, because this will release a register over a longer range of code, reducing the chance that we'll need to evict again - is still available. (After all, we &lt;i&gt;do&lt;/i&gt;&amp;nbsp;always know the last use, even if we don't necessarily know the first definition).&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Altogether, I'm quite excited about this algorithm; I think it will be a real simplification over the current implementation. Whether that will work out remains to be seen of course. I'll let you know!&lt;/div&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="http://brrt-to-the-future.blogspot.com/feeds/8209230802915789540/comments/default" title="Reacties posten"/>
    <link rel="replies" type="text/html" href="http://brrt-to-the-future.blogspot.com/2019/03/reverse-linear-scan-allocation-is.html#comment-form" title="3 reacties"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/8209230802915789540"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/8209230802915789540"/>
    <link rel="alternate" type="text/html" href="http://brrt-to-the-future.blogspot.com/2019/03/reverse-linear-scan-allocation-is.html" title="Reverse Linear Scan Allocation is probably a good idea"/>
    <author>
      <name>Bart Wiegmans</name>
      <uri>http://www.blogger.com/profile/05760700924227974153</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>3</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-7864497598813874355.post-304355411082818059</id>
    <published>2019-03-17T06:23:00.002-07:00</published>
    <updated>2019-03-17T06:57:44.591-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <title type="text">Something about IR optimization</title>
    <content type="html">Hi hackers! Today I want to write about optimizing IR in the MoarVM JIT, and also a little bit about IR design itself.&lt;br /&gt;
&lt;br /&gt;
One of the (major) design goals for the expression JIT was to have the ability to optimize code over the boundaries of individual MoarVM instructions. To enable this, the expression JIT first expands each VM instruction into a graph of lower-level operators. Optimization then means pattern-matching those graphs and replacing them with more efficient expressions.&lt;br /&gt;
&lt;br /&gt;
As a running example, consider the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;idx&lt;/span&gt; operator. This operator takes two inputs (&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;base&lt;/span&gt; and &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;element&lt;/span&gt;) and a constant parameter &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;scale&lt;/span&gt; and computes &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;base+element*scale&lt;/span&gt;. This represents one of the operands of an&amp;nbsp; 'indexed load' instruction on x86, typically used to process arrays. Such instructions allow one instruction to be used for what would otherwise be two operations (computing an address and loading a value). However, if the element of the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;idx&lt;/span&gt; operator is a constant, we can replace it instead with the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;addr&lt;/span&gt; instruction, which just adds a constant to a pointer. This is an improvement over &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;idx&lt;/span&gt; because we no longer need to load the value of element into a register. This saves both an instruction and valuable register space.&lt;br /&gt;
&lt;br /&gt;
Unfortunately this optimization introduces a bug. (Or, depending on your point of view, brings an existing bug out into the open). The expression JIT code generation process selects instructions for subtrees (tile) of the graph in a bottom-up fashion. These instructions represent the value computed or work performed by that subgraph. (For instance, a tree like&amp;nbsp;&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;(load (addr ? 8) 8)&lt;/span&gt; becomes &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;mov ?, qword [?+8]&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;; the question marks are filled in during register allocation). Because an instruction is always represents a &lt;i&gt;tree&lt;/i&gt;, and because the graph is an arbitrary &lt;i&gt;directed acyclic graph&lt;/i&gt;, the code generator projects that graph as a tree by visiting each operator node only once. So each value is computed once, and that computed value is reused by all later references.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;
It is worth going into some detail into why the expression graph is not a tree. Aside from transformations that might be introduced by optimizations (e.g. common subexpression elimination), a template may introduce a value that has multiple references via the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;let:&lt;/span&gt; pseudo-operator. See for instance the following (simplified) template:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;(let: (($foo (&lt;span style="color: red;"&gt;load&lt;/span&gt; (local))))&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;&amp;nbsp; &amp;nbsp; (add &lt;span style="color: red;"&gt;$foo&lt;/span&gt; (sub &lt;span style="color: red;"&gt;$foo&lt;/span&gt; (const 1))))&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgSrA73CFVJNjTtip0-9OR3cDZLU3EICP5pkQEDqQiUpmK04BSDWv4xoBMk1JXxqSGLoCUMSTe4kNaPlFgIsVlor7c4XpHEi-rajShraLgiiqoLUPMseLPgSS2v1ugG-Up6O7SsJmvR9c/s1600/tree-1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" data-original-height="130" data-original-width="493" height="105" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgSrA73CFVJNjTtip0-9OR3cDZLU3EICP5pkQEDqQiUpmK04BSDWv4xoBMk1JXxqSGLoCUMSTe4kNaPlFgIsVlor7c4XpHEi-rajShraLgiiqoLUPMseLPgSS2v1ugG-Up6O7SsJmvR9c/s400/tree-1.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Both ADD and SUB refer to the same LOAD node&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
In this case, both references to &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;$foo&lt;/span&gt; point directly to the &lt;i&gt;same&lt;/i&gt;&amp;nbsp;&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;load&lt;/span&gt; operator. Thus, the graph is not a tree. Another case in which this occurs is during linking of templates into the graph. The output of an instruction is used, if possible, directly as the input for another instruction. (This is the primary way that the expression JIT can get rid of unnecessary memory operations). But there can be multiple instructions that use a value, in which case an operator can have multiple references. Finally, instruction operands are inserted by the compiler and these can have multiple references as well.&lt;br /&gt;
&lt;br /&gt;
If each operator is visited only once during code generation, then this may introduce a problem when combined with another feature - conditional expressions. For instance, if two branches of a conditional expression both refer to the same value (represented by name &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;$foo&lt;/span&gt;) then the code generator will only emit code to compute its value when it encounters the &lt;i&gt;first&lt;/i&gt;&amp;nbsp;reference. When the code generator encounters &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;$foo&lt;/span&gt; for the second time in the other branch, &lt;i&gt;no code will be emitted.&lt;/i&gt;&amp;nbsp;This means that in the second branch, &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;$foo&lt;/span&gt; will effectively have no defined value (because the code in the first branch is never executed), and wrong values or memory corruption is then the predictable result.&lt;br /&gt;
&lt;br /&gt;
This bug has always existed for as long as the expression JIT has been under development, and in the past the solution has been not to write templates which have this problem. This is made a little easier by a feature the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;let:&lt;/span&gt; operator, in that it inserts a &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;do&lt;/span&gt; operator which orders the values that are declared to be computed before the code that references them. So that this is in fact non-buggy:&lt;br /&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;(let: (($foo (load (local))) # code to compute $foo is emitted here&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;&amp;nbsp; (if (...)&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;&amp;nbsp; &amp;nbsp; (add $foo (const 1)) # $foo is just a reference&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;&amp;nbsp; &amp;nbsp; (sub $foo (const 2)) # and here as well&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil8wV6lSZdDoULUkrk6JawqzLjBL0gODGAh1rEIPN-cnjtHg1IQju4iLzmuAVPmzPIyVY2CnotdPIKQgrtVkrI9YOHSDHX7uZnCSbihzm503nkomghlk3ceVccZSze4M5tUYeqweKgF8E/s1600/tree-2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" data-original-height="264" data-original-width="613" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil8wV6lSZdDoULUkrk6JawqzLjBL0gODGAh1rEIPN-cnjtHg1IQju4iLzmuAVPmzPIyVY2CnotdPIKQgrtVkrI9YOHSDHX7uZnCSbihzm503nkomghlk3ceVccZSze4M5tUYeqweKgF8E/s400/tree-2.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;The DO node is inserted for the LET operator. It ensures that the value of the LOAD node is computed before the reference in either branch&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
Alternatively, if a value &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;$foo&lt;/span&gt; is used in the condition of the if operator, you can also be sure that it is available in both sides of the condition.&lt;br /&gt;
&lt;br /&gt;
All these methods rely on the programmer being able to predict when a value will be first referenced and hence evaluated. An optimizer breaks this by design. This means that if I want the JIT optimizer to be successful, my options are:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Fix the optimizer so as to not remove references that are critical for the correctness of the program&lt;/li&gt;
&lt;li&gt;Modify the input tree so that such references are either copied or moved forward&lt;/li&gt;
&lt;li&gt;Fix the code generator to emit code for a value, if it determines that an earlier reference is not available from the current block.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
In other words, I first need to decide where this bug really belongs - in the optimizer, the code generator, or even the IR structure itself. The weakness of the expression IR is that expressions don't really impose a particular order. (This is unlike the spesh IR, which is instruction-based, and in which every instruction has a 'previous' and 'next' pointer). Thus, there really isn't a 'first' reference to a value, before the code generator introduces the concept. This is property is in fact quite handy for optimization (for instance, we can evaluate operands in whatever order is best, rather than being fixed by the input order) - so I'd really like to preserve it. But it also means that the property we're interested in - a value is computed before it is used in, in all possible code flow paths - isn't really expressible by the IR. And there is no obvious &lt;i&gt;local invariant&lt;/i&gt;&amp;nbsp;that can be maintained to ensure that this bug does not happen, so any correctness check may have to check the entire graph, which is quite impractical.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I hope this post explains why this is such a tricky problem! I have some ideas for how to get out of this, but I'll reserve those for a later post, since this one has gotten quite long enough. Until next time!&lt;/div&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="http://brrt-to-the-future.blogspot.com/feeds/304355411082818059/comments/default" title="Reacties posten"/>
    <link rel="replies" type="text/html" href="http://brrt-to-the-future.blogspot.com/2019/03/something-about-ir-optimization.html#comment-form" title="1 reacties"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/304355411082818059"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/304355411082818059"/>
    <link rel="alternate" type="text/html" href="http://brrt-to-the-future.blogspot.com/2019/03/something-about-ir-optimization.html" title="Something about IR optimization"/>
    <author>
      <name>Bart Wiegmans</name>
      <uri>http://www.blogger.com/profile/05760700924227974153</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgSrA73CFVJNjTtip0-9OR3cDZLU3EICP5pkQEDqQiUpmK04BSDWv4xoBMk1JXxqSGLoCUMSTe4kNaPlFgIsVlor7c4XpHEi-rajShraLgiiqoLUPMseLPgSS2v1ugG-Up6O7SsJmvR9c/s72-c/tree-1.png" height="72" width="72"/>
    <thr:total>1</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-7864497598813874355.post-8448977558433441573</id>
    <published>2019-01-14T13:34:00.002-08:00</published>
    <updated>2019-01-14T13:34:41.218-08:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <title type="text">A short post about types and polymorphism</title>
    <content type="html">Hi all. I usually write somewhat long-winded posts, but today I'm going to try and make an exception. Today I want to talk about the expression template language used to map the high-level MoarVM instructions to low-level constructs that the JIT compiler can easily work with:&lt;br /&gt;
&lt;br /&gt;
This 'language' was designed back in 2015 subject to three constraints:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;It should make it easy to develop 'templates' for MoarVM instructions, so we can map the ~800 or so different instructions supported by the interpreter to something the JIT compiler can work with.&lt;/li&gt;
&lt;li&gt;It should be simple to process and analyze; specifically, it should be suitable as input to the instruction selection process (the tiler).&lt;/li&gt;
&lt;li&gt;It should be simple to implement, both from the frontend (meaning the perl program that compiles a template file to a C header) and the backend (meaning the C code that combines templates into the IR that is compiled).&lt;/li&gt;
&lt;/ul&gt;
Recently I've been working on adding support for floating point operations, and&amp;nbsp; this means working on the type system of the expression language. Because floating point instructions operate on a distinct set of registers from integer instructions, a floating point operator is not interchangeable with an integer (or pointer) operator.&lt;br /&gt;
&lt;br /&gt;
This type system is enforced in two ways. First, by the template compiler, which attempts to check if you've used all operands correctly. This operates during development, which is convenient. Second, by instruction selection, as there will simply not be any instructions available that have the wrong combinations of types. Unfortunately, that happens at runtime, and such errors so annoying to debug that it motivated the development of the first type checker.&lt;br /&gt;
&lt;br /&gt;
However, this presents two problems. One of the advantages of the expression IR is that, by virtue of having a small number of operators, it is fairly easy to analyze. Having a distinct set of operators for each type would undo that. But more importantly, there are several MoarVM instructions that are &lt;i&gt;generic&lt;/i&gt;, i.e. that operate on integer, floating point, and pointer values. (For example, the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;set&lt;/span&gt;, &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;getlex&lt;/span&gt; and &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;bindlex&lt;/span&gt; instructions are generic in this way). This makes it impossible to know whether its values will be integers, pointers, or floats.&lt;br /&gt;
&lt;br /&gt;
This is no problem for the interpreter since it can treat values as bags-of-bits (i.e., it can simply copy the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;union MVMRegister&lt;/span&gt; type that holds all values of all supported types). But the expression JIT works differently - it assumes that it can place any value in a register, and that it can reorder and potentially skip storing them to memory. (This saves work when the value would soon be overwritten anyway). So we need to know what register class that is, and we need to have the correct &lt;i&gt;operators&lt;/i&gt; to manipulate a value in the right register class.&lt;br /&gt;
&lt;br /&gt;
To summarize, the problem is:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;We need to know the type of each value, both to ensure we use the correct instructions and the right registers.&lt;/li&gt;
&lt;li&gt;There are several cases in which we don't really know (for the template) what type each value has.&lt;/li&gt;
&lt;/ul&gt;
There are two ways around this, and I chose to use both. First, we know as a fact for each local or lexical value in a MoarVM frame (subroutine) what type it should have. So even a generic operator like &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;set&lt;/span&gt; can be resolved to a specific type at runtime, at which point we can select the correct operators. Second, we can introduce generic operators of our own. This is possible so long as we can select the correct instruction for an operator based on the types of the operands.&lt;br /&gt;
&lt;br /&gt;
For instance, the &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;store&lt;/span&gt; operator takes two operands, an address and a value. Depending on the type of the value (&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;reg&lt;/span&gt; or &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;num&lt;/span&gt;), we can always select the correct instruction (&lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;mov&lt;/span&gt; or &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;movsd&lt;/span&gt;). It is however &lt;i&gt;not&lt;/i&gt; possible to select different instructions for the&lt;span style="font-family: inherit;"&gt; &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;load&lt;/span&gt; operator based on the type required, because instruction selection works from the bottom up. So we need a special &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;load_num&lt;/span&gt; operator, but a &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;store_num&lt;/span&gt; operator is not necessary.&lt;span style="font-family: inherit;"&gt; &lt;/span&gt;And this is true for a &lt;i&gt;lot&lt;/i&gt; more operators than I had initially thought. For instance, aside from the (naturally generic) &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;do&lt;/span&gt; and &lt;span style="font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;"&gt;if&lt;/span&gt; operators, all arithmetic operators and comparison operators &lt;/span&gt;are generic in this way.&lt;br /&gt;
&lt;br /&gt;
I realize that, despite my best efforts, this has become a rather long-winded post anyway.....&lt;br /&gt;
&lt;br /&gt;
Anyway. For the next week, I'll be taking a slight detour, and I aim to generalize the two-operand form conversion that is necessary on x86. I'll try to write a blog about it as well, and maybe it'll be short and to the point. See you later!</content>
    <link rel="replies" type="application/atom+xml" href="http://brrt-to-the-future.blogspot.com/feeds/8448977558433441573/comments/default" title="Reacties posten"/>
    <link rel="replies" type="text/html" href="http://brrt-to-the-future.blogspot.com/2019/01/a-short-posts-about-types-and.html#comment-form" title="0 reacties"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/8448977558433441573"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7864497598813874355/posts/default/8448977558433441573"/>
    <link rel="alternate" type="text/html" href="http://brrt-to-the-future.blogspot.com/2019/01/a-short-posts-about-types-and.html" title="A short post about types and polymorphism"/>
    <author>
      <name>Bart Wiegmans</name>
      <uri>http://www.blogger.com/profile/05760700924227974153</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry>
    <title>Perl 6 Coding Contest 2019: Seeking Task Makers</title>
    <link rel="alternate" href="http://perlgeek.de/blog-en/perl-6/2018-perl6-coding-contest-seeking-task-makers.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><!-- 2018-11-11 -->

<p>I want to revive <a href="http://strangelyconsistent.org/blog/masaks-perl-6-coding-contest">Carl Mäsak's Coding Contest</a>
as a <a href="https://gist.github.com/moritz/6f06ec7153ce396ac2734c2616d8b075">crowd-sourced contest</a>.</p>

<p>The contest will be in four phases:</p>

<ul>
<li>development of tasks</li>
<li>public contest, where you can solve the tasks</li>
<li>public commenting on solutions</li>
<li>grading and awarding of prizes</li>
</ul>

<p>For the first phase, development of tasks, I am looking for volunteers who
come up with coding tasks collaboratively. Sadly, these volunteers, including
myself, will be excluded from participating in the second phase.</p>

<p>I am looking for tasks that ...</p>

<ul>
<li>are well-worded</li>
<li>have a (private) implementation that shows it is solvable, preferably
in under 500 lines of code</li>
<li>have a few public tests to help the participants, and a more tests
tests that help the graders and commenters later on</li>
</ul>

<p>This is non-trivial, so I'd like to have others to discuss things with,
and to come up with some more tasks.</p>

<p>If you want to help with task creation, please send an email to <a href="mailto:moritz.lenz@gmail.com">moritz.lenz@gmail.com</a>, stating your intentions to help, and your freenode IRC handle (optional).</p>

<p>There are other ways to help too:</p>

<ul>
<li>You can pledge a prize (some ideas: <a href="https://commaide.com/">Comma IDE</a> subscription,
books, Camelia plushies, Amazon vouchers)</li>
<li>You can help design a small website for the contest</li>
<li>You can help iron out the exact rules for the contest</li>
<li>... or any other way that I didn't think of :-)</li>
</ul>

<p>In these cases you can use the same email address to contact me,
or use IRC (<code>moritz</code> on freenode) or <a href="https://twitter.com/nogoodnickleft">twitter</a>.</p>




</div>
    </content>
    <author>
      <name>Moritz Lenz</name>
    </author>
    <id>http://perlgeek.de/blog-en/perl-6/2018-perl6-coding-contest-seeking-task-makers.html</id>
    <published>2018-11-10T23:00:01+01:00</published>
    <updated>2018-11-10T23:00:01+01:00</updated>
  </entry>
  <entry>
    <title>Swiss Perl Workshop 2017</title>
    <link rel="alternate" href="https://stmuk.wordpress.com/2017/08/30/swiss-perl-workshop-2017/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p><img data-attachment-id="25" data-permalink="https://stmuk.wordpress.com/cropped-lake_castle1-jpeg/" data-orig-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg" data-orig-size="1440,1080" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="cropped-lake_castle1.jpeg" data-image-description="" data-image-caption="" data-medium-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg?w=300" data-large-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg?w=1024" class="alignnone size-full wp-image-25" src="https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg?w=1100" alt="cropped-lake_castle1.jpeg" srcset="https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg 1440w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg?w=150&amp;h=113 150w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg?w=300&amp;h=225 300w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg?w=768&amp;h=576 768w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/cropped-lake_castle1.jpeg?w=1024&amp;h=768 1024w" sizes="(max-width: 1440px) 100vw, 1440px"/></p>
<p><span style="font-weight:400;">After a perilous drive up a steep, narrow, winding road from Lake Geneva we arrived at an attractive Alpine village (Villars-sur-Ollon) to meet with fellow Perl Mongers in a small restaurant.  There followed much talk and a little clandestine drinking of exotic spirits including Swiss whisky. The following morning walking to the conference venue there was an amazing view of mountain ranges. On arrival I failed to operate the Nespresso machine which I later found was due to it simply being off.  Clearly software engineers should never try to use hardware. At least after an evening of drinking. </span></p>
<p><span style="font-weight:400;">Wendy’s stall was piled high with swag including new Bailador (Perl 6 dancer like framework) stickers, a Shadowcat booklet about Perl 6 and the new O’Reilly “Thinking in Perl 6″. Unfortunately she had sold out of Moritz’s book “Perl 6 Fundamentals” (although there was a sample display copy present). Thankfully later that morning I discovered I had a £3 credit on Google Play Books so I bought the ebook on my phone.</span></p>
<p><span style="font-weight:400;">The conference started early with Damian Conway’s Three Little Words.  These were “has”, “class” and “method” from Perl 6 which he liked so much that he had added them to Perl 5 with his “Dios” – “Declarative Inside-Out Syntax” module.  PPI wasn’t fast enough so he had to replace it with a 50,000 character regex PPR. Practical everyday modules mentioned included Regexp::Optimizer and Test::Expr. If the video  doesn’t appear shortly on youtube a version of his talk dating from a few weeks earlier is available at </span><a href="https://www.youtube.com/watch?v=ob6YHpcXmTg"><span style="font-weight:400;">https://www.youtube.com/watch?v=ob6YHpcXmTg</span></a></p>
<p><span style="font-weight:400;">Jonathan Worthington returned with his Perl 6 talk on “How does deoptimization help us go faster?” giving us insight into why Perl 6 was slow at the Virtual Machine level (specifically MoarVM). Even apparently simple and fast operations like indexing an array were slow due to powerful abstractions, late binding and many levels of Multiple Dispatch. In short the flexibility and power of such an extensible language also led to slowness due to the complexity of code paths. The AST optimizer helped with this at compile time but itself took time and it could be better to do this at a later compile time (like Just In Time).  Even with a simple program reading lines from a file it was very hard to determine statically what types were used (even with type annotations) and whether it was worth optimizing (since the file could be very short).</span></p>
<p><span style="font-weight:400;">The solution to these dynamic problems was also dynamic but to see what was happening needed cheap logging of execution which was passed to another thread.  This logging is made visible by setting the environment variable MVM_SPESH_LOG to a filename. Better tooling for this log would be a good project for someone.</span></p>
<p><span style="font-weight:400;">For execution planning we look for hot (frequently called) code, long blocks of bytecode (slow to run) and consider how many types are used (avoiding “megamorphic” cases with many types which needs many versions of code).  Also analysis of the code flow between different code blocks and SSA.  Mixins made the optimization particularly problematic.</span></p>
<p><span style="font-weight:400;">MoarVM’s Spesh did statistical analysis of the code in order to rewrite it in faster, simpler ways. Guards (cheap check for things like types) were placed to catch cases where it got it wrong and if these were triggered (infrequently) it would deoptimize as well, hence the counterintuitive title since “Deoptimization enables speculation” The slides are at </span><a href="http://jnthn.net/papers/2017-spw-deopt.pdf"><span style="font-weight:400;">http://jnthn.net/papers/2017-spw-deopt.pdf</span></a><span style="font-weight:400;"> with the video at </span><a href="https://www.youtube.com/watch?v=3umNn1KnlCY"><span style="font-weight:400;">https://www.youtube.com/watch?v=3umNn1KnlCY</span></a><span style="font-weight:400;"> The older and more dull witted of us (including myself) might find the latter part of the video more comprehensible at 0.75 Youtube speed.</span></p>
<p><span style="font-weight:400;">After a superb multi-course lunch (the food was probably the best I’d had at any Perl event) we returned promptly to hear Damian talk of “Everyday Perl 6”. He pointed out that it wasn’t necessary to code golf obfuscated extremes of Perl 6 and that the average Perl 5 programmer would see many things simpler in Perl 6.  Also a rewrite from 5 to 6 might see something like 25% fewer lines of code since 6 was more expressive in syntax (as well as more consistent) although performance problems remained (and solutions in progress as the previous talk had reminded us).</span></p>
<p><span style="font-weight:400;">Next Liz talked of a “gross” (in the numerical sense of 12 x 12 rather than the American teen sense) of Perl 6 Weeklies as she took us down memory lane to 2014 (just about when MoarVM was launched and when unicode support was poor!)  with some selected highlights and memories of Perl 6 developers of the past (and hopefully future again!). Her talk was recorded at </span><a href="https://www.youtube.com/watch?v=418QCTXmvDU"><span style="font-weight:400;">https://www.youtube.com/watch?v=418QCTXmvDU</span></a></p>
<p><img data-attachment-id="46" data-permalink="https://stmuk.wordpress.com/newton/" data-orig-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg" data-orig-size="3264,2448" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;2.2&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;iPhone 6&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1503676921&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;4.15&quot;,&quot;iso&quot;:&quot;50&quot;,&quot;shutter_speed&quot;:&quot;0.03030303030303&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;,&quot;latitude&quot;:&quot;46.294861111111&quot;,&quot;longitude&quot;:&quot;7.0555111111111&quot;}" data-image-title="newton" data-image-description="" data-image-caption="" data-medium-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=300" data-large-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=1024" class="alignnone size-full wp-image-46" src="https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=1100" alt="newton" srcset="https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg 3264w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=150&amp;h=113 150w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=300&amp;h=225 300w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=768&amp;h=576 768w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=1024&amp;h=768 1024w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/newton.jpg?w=1440&amp;h=1080 1440w" sizes="(max-width: 3264px) 100vw, 3264px"/></p>
<p><span style="font-weight:400;">Cal then spoke of Perl 6 maths which he thought was good with its Rats and FatRats but not quite good enough and his ideas of fixing it.  On the following day he showed us he had started some TDD work on TrimRats. He also told us that Newton’s Method wasn’t very good but generated a pretty fractal. See </span><a href="https://www.youtube.com/watch?v=3na_Cx-anvw"><span style="font-weight:400;">https://www.youtube.com/watch?v=3na_Cx-anvw</span></a></p>
<p><span style="font-weight:400;">Lee spoke about how to detect Perl 5 memory leaks with various CPAN modules and his examples are at </span><a href="https://github.com/leejo/Perl_memory_talk"><span style="font-weight:400;">https://github.com/leejo/Perl_memory_talk</span></a></p>
<p><span style="font-weight:400;">The day finished with Lightning Talks and a barbecue at givengain — a main sponsor.</span></p>
<p>On the second day I noticed the robotic St Bernards dog in a tourist shop window had come to life.</p>
<p><img data-attachment-id="44" data-permalink="https://stmuk.wordpress.com/dog1/" data-orig-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/dog1.gif" data-orig-size="600,338" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="dog1" data-image-description="" data-image-caption="" data-medium-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/dog1.gif?w=300" data-large-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/dog1.gif?w=600" class="alignnone size-full wp-image-44" src="https://stmuk.wordpress.com/wp-content/uploads/2017/08/dog1.gif?w=1100" alt="dog1" srcset="https://stmuk.wordpress.com/wp-content/uploads/2017/08/dog1.gif 600w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/dog1.gif?w=150&amp;h=85 150w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/dog1.gif?w=300&amp;h=169 300w" sizes="(max-width: 600px) 100vw, 600px"/></p>
<p><span style="font-weight:400;">Damian kicked off the talks with my favourite of his talks,  “Standing on the Shoulders of Giants”, starting with the Countess of Lovelace and her Bernoulli number program. This generated a strange sequence with many zeros. The Perl 6 version since it used rational numbers not floating point got the zeros right whereas the Perl 5 version initially suffered from floating point rounding errors (which are fixable).</span></p>
<p><span style="font-weight:400;">Among other things he showed us how to define a new infix operator in Perl 6. He also showed us a Perl 6 sort program that looked exactly like LISP even down to the Lots of Irritating Superfluous Parentheses. I think this was quicksort (he certainly showed us a picture of Sir Tony Hoare at some point). Also a very functional (Haskell-like) equivalent  with heavy use of P6 Multiple Dispatch.  Also included was demonstration of P6 “before” as a sort of typeless/multi-type comparison infix. Damian then returned to his old favourite of Quantum Computing.</span></p>
<p><span style="font-weight:400;">My mind and notes got a bit jumbled at this point but I particularly liked the slide that explained how factorisation could work by observing the product of possible inputs since this led to a collapse that revealed the factors.  To do this on RSA etc., of course, needs real hardware support which probably only the NSA and friends have (?). Damian’s code examples are at </span><a href="http://www.bit.do/Perl6SOG"><span style="font-weight:400;">http://www.bit.do/Perl6SOG</span></a><span style="font-weight:400;"> with  an earlier version of his talk at </span><a href="https://www.youtube.com/watch?v=Nq2HkAYbG5o"><span style="font-weight:400;">https://www.youtube.com/watch?v=Nq2HkAYbG5o</span></a><span style="font-weight:400;"> Around this point there was a road race of classic cars going on outside up the main road into the village and there were car noises in the background that strangely were more relaxing than annoying.</span></p>
<p><img loading="lazy" data-attachment-id="57" data-permalink="https://stmuk.wordpress.com/2017/08/30/swiss-perl-workshop-2017/file_000/" data-orig-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg" data-orig-size="3264,2448" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;2.2&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;iPhone 6&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1503771021&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;4.15&quot;,&quot;iso&quot;:&quot;32&quot;,&quot;shutter_speed&quot;:&quot;0.004739336492891&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;,&quot;latitude&quot;:&quot;46.294783333333&quot;,&quot;longitude&quot;:&quot;7.0559888888889&quot;}" data-image-title="File_000" data-image-description="" data-image-caption="" data-medium-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=300" data-large-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=1024" class="alignnone size-full wp-image-57" src="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=1100" alt="File_000" srcset="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg 3264w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=150&amp;h=113 150w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=300&amp;h=225 300w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=768&amp;h=576 768w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=1024&amp;h=768 1024w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000.jpeg?w=1440&amp;h=1080 1440w" sizes="(max-width: 3264px) 100vw, 3264px"/></p>
<p><span style="font-weight:400;">After Quantum Chaos Paul Johnson brought us all back down to ground with an excellent practical talk on modernising legacy Perl 5 applications based on his war stories. Hell, of course, is “Other People’s Code”, often dating from Perl’s early days and lacking documentation and sound engineering.</span></p>
<p><span style="font-weight:400;">Often the original developers had long since departed or, in the worse cases, were still there.  Adding tests and logging (with stack traces) were particularly useful. As was moving to git (although its steep learning curve meant mentoring was needed) and handling CPAN module versioning with pinto.  Many talks had spoken of the Perl 6 future whereas this spoke of the Perl 5 past and present and the work many of us suffer to pay the bills. It’s at </span><a href="https://www.youtube.com/watch?v=4G5EaUNOhR0"><span style="font-weight:400;">https://www.youtube.com/watch?v=4G5EaUNOhR0</span></a></p>
<p><img loading="lazy" data-attachment-id="63" data-permalink="https://stmuk.wordpress.com/2017/08/30/swiss-perl-workshop-2017/file_000-1/" data-orig-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg" data-orig-size="3264,2448" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;2.2&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;iPhone 6&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1503747734&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;4.15&quot;,&quot;iso&quot;:&quot;50&quot;,&quot;shutter_speed&quot;:&quot;0.03030303030303&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;,&quot;latitude&quot;:&quot;46.294861111111&quot;,&quot;longitude&quot;:&quot;7.0555111111111&quot;}" data-image-title="File_000 (1)" data-image-description="" data-image-caption="" data-medium-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=300" data-large-file="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=1024" class="alignnone size-full wp-image-63" src="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=1100" alt="File_000 (1)" srcset="https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg 3264w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=150&amp;h=113 150w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=300&amp;h=225 300w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=768&amp;h=576 768w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=1024&amp;h=768 1024w, https://stmuk.wordpress.com/wp-content/uploads/2017/08/file_000-1.jpeg?w=1440&amp;h=1080 1440w" sizes="(max-width: 3264px) 100vw, 3264px"/></p>
<p><span style="font-weight:400;">Jonathan then spoke of reactive distributed software.  A distributed system is an async one where “Is it working?” means “some of it is working but we don’t know which bits”.  Good OO design is “tell don’t ask” — you tell remote service to do something for you and not parse the response and do it yourself thus breaking encapsulation.  This is particularly important in building well designed distributed systems since otherwise the systems are less responsive and reliable.  Reactive (async) works better for distributed software than interactive (blocking or sync).</span></p>
<p><span style="font-weight:400;">We saw a table that used a Perl 6 promise for one value and a supply for many values for reactive (async) code and the equivalent (one value) and a Perl 6 Seq for interactive code. A Supply could be used for pub/sub and the Observer Pattern. A Supply could either be live (like broadcast TV) or, for most Perl 6 supplies, on-demand (like Netflix). Then samples of networking (socket) based code were discussed including a web client, web server and SSH::LibSSH (async client bindings often very useful in practical applications like port forwarding)</span></p>
<p><a href="https://github.com/jnthn/p6-ssh-libssh"><span style="font-weight:400;">https://github.com/jnthn/p6-ssh-libssh</span></a></p>
<p><span style="font-weight:400;">Much of the socket code had a pattern of “react { whenever {” blocks with “whenever” as a sort of async loop.He then moved on from sockets to services (using a Supply pipeline) and amazed us by announcing the release of “cro”, a microservices library that even supports HTTP/2 and Websockets, at </span><a href="http://mi.cro.services"><span style="font-weight:400;">http://mi.cro.services</span></a><span style="font-weight:400;">/.  This is installable using Perl 6 by “zef install –/test cro”.</span></p>
<p><span style="font-weight:400;">Slides at </span><a href="http://jnthn.net/papers/2017-spw-sockets-services.pdf"><span style="font-weight:400;">http://jnthn.net/papers/2017-spw-sockets-services.pdf</span></a><span style="font-weight:400;"> and video at </span><a href="https://www.youtube.com/watch?v=6CsBDnTUJ3A"><span style="font-weight:400;">https://www.youtube.com/watch?v=6CsBDnTUJ3A</span></a></p>
<p><span style="font-weight:400;">Next Lee showed Burp Scanner which is payware but probably the best web vulnerabilities scanner. I wondered if anyone had dare run it on ACT or the hotel’s captive portal.</span></p>
<p><span style="font-weight:400;">Wendy did some cheerleading in her “Changing Image of Perl”.  An earlier version is at </span><a href="https://www.youtube.com/watch?v=Jl6iJIH7HdA"><span style="font-weight:400;">https://www.youtube.com/watch?v=Jl6iJIH7HdA</span></a></p>
<p><span style="font-weight:400;">Sue’s talk was “Spiders, Gophers, Butterflies” although the latter were mostly noticeably absent. She promises me that a successor version of the talk will use them more extensively. Certainly any Perl 6 web spidering code is likely to fit better on one slide than the Go equivalent.</span></p>
<p><span style="font-weight:400;">During the lightning talks Timo showed us a very pretty Perl 6 program using his SDL2::Raw to draw an animated square spiral with hypnotic colour cycling type patterns. Also there was a talk by the author about </span><a href="https://bifax.org/bif/"><span style="font-weight:400;">https://bifax.org/bif/</span></a><span style="font-weight:400;">— a distributed bug tracking system (which worked offline like git).</span></p>
<p><span style="font-weight:400;">Later in the final evening many of us ate and chatted in another restaurant where we witnessed a dog fight being narrowly averted and learnt that Wendy didn’t like Perl 5’s bless for both technical and philosophical reasons.</span></p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">After a perilous drive up a steep, narrow, winding road from Lake Geneva we arrived at an attractive Alpine village (Villars-sur-Ollon) to meet with fellow Perl Mongers in a small restaurant.  There followed much talk and a little clandestine drinking of exotic spirits including Swiss whisky. The following morning walking to the conference venue there … <a href="https://stmuk.wordpress.com/2017/08/30/swiss-perl-workshop-2017/" class="more-link">Continue reading <span class="screen-reader-text">Swiss Perl Workshop 2017</span> <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>stmuk</name>
    </author>
    <id>http://stmuk.wordpress.com/?p=47</id>
    <published>2017-08-30T17:48:17Z</published>
    <updated>2017-08-30T17:48:17Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>My Ten Years of Perl 6</title>
    <link rel="alternate" href="http://perlgeek.de/blog-en/perl-6/2017-020-ten-years.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><!-- 2017-08-09 -->

<p>Time for some old man's reminiscence. Or so it feels when I realize that
I've spent more than 10 years involved with the Perl 6 community.</p>

<h2>How I Joined the Perl 6 Community</h2>

<p>It was February 2007.</p>

<p>I was bored. I had lots of free time (crazy to imagine that now...), and I spent some of that answering
(Perl 5) questions on perlmonks. There was a category of questions where
I routinely had no good answers, and those were related to threads. So I
decided to play with threads, and got frustrated pretty quickly.</p>

<p>And then I remember that a friend in school had told me (about four
years earlier) that there was this
Perl 6 project that wanted to do concurrency <em>really</em> well, and even
automatically parallelize some stuff. And this was some time ago, maybe
they had gotten anywhere?</p>

<p>So I searched the Internet, and found out about Pugs, a Perl 6 compiler
written in Haskell. And I wanted to learn more, but some of the links to
the presentations were dead. I <a href="https://irclog.perlgeek.de/perl6/2007-02-04#i_-55445">joined the #perl6 IRC channel to report
the broken link</a>.</p>

<p>And within three minutes I got a "thank you" for the report, the broken
links were gone, <em>and</em> I had an invitation for a commit bit to the
underlying SVN repo.</p>

<p>I stayed.</p>

<h2>The Early Days</h2>

<p>Those were they wild young days of Perl 6 and Pugs. Audrey Tang was
pushing Pugs (and Haskell) very hard, and often implemented a feature
within 20 minutes after somebody mentioned it. Things were unstable,
broken often, and usually fixed quickly. No idea was too crazy to be
considered or even implemented.</p>

<p>We had bots that evaluated Perl 6 and Haskell code, and gave the result
directly on IRC. There were lots of cool (and sometimes somewhat
frightening) automations, for example for inviting others to the SVN
repo, to the shared hosting system (called feather), for searching SVN logs
and so on. Since git was still an obscure and very unusable, people
tried to use <a href="https://en.wikipedia.org/wiki/SVK">SVK</a>, an attempt to
implement a decentralized version control system on top of of the SVN
protocol.</p>

<p>Despite some half-hearted attempts, I didn't really make inroads into
compiler developments. Having worked with neither Haskell nor compilers
before proved to be a pretty steep step. Instead I focused on some
early modules, documentation, tests, and asking and answering questions.
When the IRC logger went offline for a while, I wrote my own, which is
still in use today.</p>

<p>I felt at home in that IRC channel and the community. When the community
asked for mentors for the Google Summer of Code project, I stepped up.
The project was a revamp of the Perl 6 test suite, and to prepare for
mentoring task, I decided to dive deeper. That made me the maintainer of
the test suite.</p>

<h2>Pet Projects</h2>

<p>I can't recount a full history of Perl 6 projects during that time
range, but I want to reflect on some projects that I considered my pet
projects, at least for some time.</p>

<ul>
<li>In early 2008 I started to contribute some patches to
<a href="https://perl6.org/">perl6.org</a>. Over time I became frustrated with
the outdated content on many Perl 6 websites, so I created
perl6-projects.org, which only contained links to up-to-date
resources. Over time, people with an actual sense of design contribute
a nice layout. Later we switched perl6.org over to the content from
perl6-projects.org. Its structure today is still mostly that of a link
collection.</li>
<li>In September 2008 I started with the <a href="https://perlgeek.de/en/article/5-to-6">Perl 5 to
6</a> blog series, which was the
de facto resource for learning Perl 6 for some years.</li>
<li>In 2009 I wrote <a href="https://github.com/moritz/json/">JSON::Tiny</a>, the
first pure-Perl 6 JSON parser. I mostly did it to become familiar with
grammars, and because the book "Real World Haskell" also developed a
JSON module.</li>
<li>May 2010 kicked off a program to make <a href="https://perlgeek.de/blog-en/perl-6/contribute-now-announce.html">contributing to Perl 6 more
accessible</a>.</li>
<li>September 2010: the Pugs SVN repository became unmaintainable. It had
accumulated the official Perl 6 test suite, some documentation,
modules, at least one IRC bot and a proverbial metric ton of other
stuff. In coordination with #perl6, I split it up into a collection of
git repositories and put them on GitHub. A decision we haven't
regretted yet. </li>
<li>In 2012 and 2016 I was part of the organization team of the German
Perl Workshop in Erlangen and Nürnberg, which both featured several
Perl 6 talks.</li>
<li>2012 saw the birth of <a href="https://docs.perl6.org/">the documentation
project</a>. Initially I was nearly the sole
contributor, and I'm very happy that, over time, others have taken over.</li>
<li>Between 2014 and 2015, our community server "feather" EOLed, so the
Perl 6 community <a href="https://perlgeek.de/blog-en/perl-6/2014-community-server-funding.html">funded a new
server</a>,
which my <a href="https://www.noris.de/">employer, noris network AG</a> kindly
hosts for free in their data center in Nürnberg, Germany.</li>
<li>In 2016 I started writing <a href="https://leanpub.com/perl6">Perl 6 by Example</a>,
which Apress later adopted and published as <a href="https://www.apress.com/us/book/9781484228982">Perl 6
Fundamentals</a>.</li>
<li>Currently I'm working on a treatise on <a href="https://leanpub.com/perl6regex">Perl 6 Regexes and
Grammars</a>, which Apress will also
publish.</li>
</ul>

<p>It is not quite clear from this (very selected) timeline, but my Perl 6
related activity dropped around 2009 or 2010. This is when I started to
work full time, moved in with my girlfriend (now wife), and started to
plan a family.</p>

<h2>Relationships</h2>

<p>The technologies and ideas in Perl 6 are fascinating, but that's not
what kept me. I came for the technology, but stayed for the community.</p>

<p>There were and are many great people in the Perl 6 community, some of
whom I am happy to call my friends. Whenever I get the chance to attend
a Perl conference, workshop or hackathon, I find a group of Perl 6
hackers to hang out and discuss with, and generally have a good time.</p>

<p>Four events stand out in my memory. In 2010 I was invited to the Open
Source Days in Copenhagen. I missed most of the conference, but spent
a day or two with (if memory serve right) Carl Mäsak, Patrick Michaud,
Jonathan Worthington and Arne Skjærholt. We spent some fun time trying
to wrap our minds around macros, the intricacies of human and computer
language, and Japanese food. (Ok, the last one was easy). Later the same
year, I attended my first YAPC::EU in Pisa, and met most of the same
crowd again -- this time joined by Larry Wall, and over three or four
days. I still fondly remember the Perl 6 hallway track from that
conference. And 2012 I flew to Oslo for a Perl 6 hackathon, with a
close-knit, fabulous group of Perl 6 hackers. Finally, the <a href="http://blogs.perl.org/users/liz/2012/08/as-some-of-you-may.html">Perl
Reunification
Summit</a>
in the beautiful town of Perl in Germany, which brought together Perl 5
and Perl 6 hackers in a very relaxed atmosphere.</p>

<p>For three of these four events, different private sponsors from the Perl
and Perl 6 community covered travel and/or hotel costs, with their only
motivation being meeting folks they liked, and seeing the community
and technology flourish.</p>

<h2>The Now</h2>

<p>The Perl 6 community has evolved a lot over the last ten years, but it is
still a very friendly and welcoming place. There are lots of "new" folks
(where "new" is everybody who joined after me, of course :D), and a
surprising number of the old guard still hang around, some more
involved, some less, all of them still very friendly and supportive</p>

<h2>The Future</h2>

<p>I anticipate that my family and other projects will continue to occupy
much of my time, and it is unlikely that I'll be writing another Perl 6
book (after the one about regexes) any time soon. But the Perl 6 community
has become a second home for me, and I don't want to miss it.</p>

<p>In the future, I see myself supporting the Perl 6 community through
infrastructure (community servers, IRC logs, running IRC bots etc.),
answering questions, writing a blog article here and there, but mostly
empowering the "new" guard to do whatever they deem best.</p>



</div>
    </content>
    <author>
      <name>Moritz Lenz</name>
    </author>
    <id>http://perlgeek.de/blog-en/perl-6/2017-020-ten-years.html</id>
    <published>2017-08-08T22:00:01+01:00</published>
    <updated>2017-08-08T22:00:01+01:00</updated>
  </entry>
  <entry>
    <title>Perl 6 Fundamentals Now Available for Purchase</title>
    <link rel="alternate" href="http://perlgeek.de/blog-en/perl-6/2017-018-perl6-fundamentals-available-for-purchase.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><!-- 2017-07-22 -->
<p>After about nine months of work, my book
<a href="https://www.apress.com/us/book/9781484228982">Perl 6 Fundamentals</a> is now available for purchase on <a href="https://www.apress.com/us/book/9781484228982">apress.com</a> and <a href="http://www.springer.com/us/book/9781484228982">springer.com</a>.</p>

<p>The ebook can be purchased right now, and comes in the epub and PDF formats (with watermarks, but DRM free). The print form can be pre-ordered from <a href="https://www.amazon.com/dp/1484228987">Amazon</a>, and will become ready for shipping in about a week or two.</p>

<p>I will make a copy of the ebook available for free for everybody who purchased an earlier version, "Perl 6 by Example", from LeanPub.</p>

<p>The book is aimed at people familiar with the basics of programming; prior
Perl 5 or Perl 6 knowledge is not required. It features a practical example in most chapters (no mammal hierarchies or <code>class Rectangle</code> inheriting from <code>class Shape</code>), ranging from simple input/output and text formatting to plotting with python's matplotlib libraries. Other examples include date and time conversion, a Unicode search tool and a directory size visualization.</p>

<p>I use these examples to explain subset of Perl 6, with many pointers to more
documentation where relevant. Perl 6 topics include the basic lexicographic
structure, testing, input and output, multi dispatch, object orientation, regexes and grammars, usage of modules, functional programming and interaction
with python libraries through <code>Inline::Python</code>.</p>

<p>Let me finish with Larry Wall's description of this book, quoted from his foreword:</p>

<blockquote>
It's not just a reference, since you can always find such
materials online.  Nor is it just a cookbook.  I like to think of it as an
extended invitation, from a well-liked and well-informed member of our circle,
to people like you who might want to join in on the fun.  Because joy is
what's fundamental to Perl.  The essence of Perl is an invitation to
love, and to be loved by, the Perl community.  It's an invitation to be a
participant of the gift economy, on both the receiving and the giving end.
</blockquote>



</div>
    </content>
    <author>
      <name>Moritz Lenz</name>
    </author>
    <id>http://perlgeek.de/blog-en/perl-6/2017-018-perl6-fundamentals-available-for-purchase.html</id>
    <published>2017-07-21T22:00:01+01:00</published>
    <updated>2017-07-21T22:00:01+01:00</updated>
  </entry>
  <entry>
    <title>The Loss of Name and Orientation</title>
    <link rel="alternate" href="http://perlgeek.de/blog-en/perl-6/2017-018-losing-named-and-orientation.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><!-- 2017-07-11 -->

<p>The <a href="https://perl6.party/post/The-Hot-New-Language-Named-Rakudo">Perl 6 naming debate has started again</a>. And I guess with good reason. Teaching people that Perl 6 is <i>a</i> Perl, but not <i>the</i> Perl requires too much effort. Two years ago, I didn't believe. Now you're reading a tired man's words.</p>

<p>I'm glad that this time, we're not discussing giving up the "Perl" brand, which still has very positive connotations in my mind, and in many other minds as well.</p>

<p>And yet, I can't bring myself to like "Rakudo Perl 6" as a name. There are two vary shallow reasons for that: Going from two syllables, "Perl six", to five of them, seems a step in the wrong direction. And two, I remember the days when the name was pretty young, and people would misspell it all the time. That seems to have abated, though I don't know why.</p>

<p>But there's also a deeper reason, probably sentimental old man's reason. I remember the days when Pugs was actively developed, and formed the center of a vibrant community. When kp6 and SMOP and all those weird projects were around. And then, just when it looked like there was only a single compiler was around, Stefan O'Rear conjured up niecza, almost single-handedly, and out of thin air. Within months, it was a viable Perl 6 compiler, that people on #perl6 readily recommended.</p>

<p>All of this was born out of the vision that Perl 6 was a language with no single, preferred compiler. Changing the language name to include the compiler name means abandoning this vision. How can we claim to welcome alternative implementations when the commitment to one compiler is right in the language name?</p>

<p>However I can't weigh this loss of vision against a potential gain in popularity. I can't decide if it's my long-term commitment to the name "Perl 6" that makes me resent the new name, or valid objections. The lack of vision mirrors my own state of mind pretty well.</p>

<p>I don't know where this leaves us. I guess I must apologize for wasting your time by publishing this incoherent mess.</p>


</div>
    </content>
    <author>
      <name>Moritz Lenz</name>
    </author>
    <id>http://perlgeek.de/blog-en/perl-6/2017-018-losing-named-and-orientation.html</id>
    <published>2017-07-10T22:00:01+01:00</published>
    <updated>2017-07-10T22:00:01+01:00</updated>
  </entry>
  <entry>
    <title>Living on the (b)leading edge</title>
    <link rel="alternate" href="http://perlgeek.de/blog-en/perl-6/2017-017-living-on-the-bleading-edge.html" type="text/html"/>
    <content type="html">&lt;!-- 2017-06-25 --&gt;

&lt;p&gt;Perl 6 is innovative in many ways, and sometimes we don't fully
appreciate all the implications, for good or for bad.&lt;/p&gt;

&lt;p&gt;There's one I stumbled upon recently: The use of fancy Unicode
symbols for built-in stuff. In this case: the `.gist` output of Match
objects. For example&lt;/p&gt;

&lt;pre&gt;
&lt;span class="synSpecial"&gt;my&lt;/span&gt; &lt;span class="synStatement"&gt;token&lt;/span&gt; word {&lt;span class="synConstant"&gt; &lt;/span&gt;&lt;span class="synSpecial"&gt;\w+&lt;/span&gt;&lt;span class="synConstant"&gt; &lt;/span&gt;}
&lt;span class="synIdentifier"&gt;say&lt;/span&gt; &lt;span class="synSpecial"&gt;'&lt;/span&gt;&lt;span class="synConstant"&gt;abc=def&lt;/span&gt;&lt;span class="synSpecial"&gt;'&lt;/span&gt; &lt;span class="synStatement"&gt;~~&lt;/span&gt; &lt;span class="synSpecial"&gt;/&amp;lt;&lt;/span&gt;word&lt;span class="synSpecial"&gt;&amp;gt;&lt;/span&gt;&lt;span class="synConstant"&gt; &lt;/span&gt;&lt;span class="synSpecial"&gt;'&lt;/span&gt;&lt;span class="synConstant"&gt;=&lt;/span&gt;&lt;span class="synSpecial"&gt;'&lt;/span&gt;&lt;span class="synConstant"&gt; &lt;/span&gt;&lt;span class="synSpecial"&gt;&amp;lt;&lt;/span&gt;word&lt;span class="synSpecial"&gt;&amp;gt;/&lt;/span&gt;&lt;span class="synStatement"&gt;;&lt;/span&gt;
&lt;/pre&gt;

produces this output:

&lt;pre&gt;
｢abc=def｣
 word =&amp;gt; ｢abc｣
 word =&amp;gt; ｢def｣
&lt;/pre&gt;

&lt;p&gt;And that's where the problems start. In my current &lt;a
href="https://leanpub.com/perl6regex"&gt;quest to write a book on Perl 6
regexes&lt;/a&gt;, I noticed that the PDF that LeanPub generates from my
Markdown sources don't correctly display those pesky ｢｣ characters,
which are

&lt;pre&gt;
$ uni -c ｢｣
｢ - U+0FF62 - HALFWIDTH LEFT CORNER BRACKET
｣ - U+0FF63 - HALFWIDTH RIGHT CORNER BRACKET
&lt;/pre&gt;

&lt;p&gt;When I copied the text from the PDF and pasted into my editor, they
showed up correctly, which indicates that the characters are likely
missing from the monospace font.&lt;/p&gt;

&lt;p&gt;The toolchain allows control over the font used for displaying code,
so I tried all the monospace fonts that were available. I tried them in
alphabetical order. Among the earlier fonts I tried was Deja Vu Sans
Mono, which I use in my terminal, and which hasn't let me down yet. No
dice. I arrived at &lt;a
href"https://www.google.com/get/noto/"&gt;Noto&lt;/a&gt;, a font designed to
cover all Unicode codepoints. And it didn't work either. So it turns out
these two characters are part of some Noto Sans variants, but not of the
monospace font.&lt;/p&gt;

&lt;p&gt;My terminal, and even some font viewers, use some kind of fallback
where they use glyphs from other fonts to render missing characters. The
book generation toolchain does not.&lt;/p&gt;

&lt;p&gt;The Google Group for Leanpub was &lt;a
href="https://groups.google.com/forum/#!topic/leanpub/bqVazrui-O4"&gt;somewhat
helpful:&lt;/a&gt; if I could recommend an Open Source mono space font that
fit my needs, they'd likely include it in their toolchain.&lt;/p&gt;

&lt;p&gt;So I searched and searched, learning more about fonts than I wanted
to know. My circle of geek friends came up with several suggestions, one
of them being &lt;a href="https://github.com/be5invis/Iosevka"&gt;Iosevka&lt;/a&gt;,
which actually contains those characters. So now I wait for others to
step up, either for LeanPub to include that font, or for &lt;a
href="https://github.com/googlei18n/noto-fonts/issues/939"&gt;the Noto
maintainers to create a monospace variant of those characters&lt;/a&gt; (and
then LeanPub updating their version of the font).&lt;/p&gt;

&lt;p&gt;And all of that because Perl 6 was being innovative, and used two
otherwise little-used characters as delimiters, in an attempt to avoid
collisions between delimiters and content.&lt;/p&gt;

&lt;p&gt;(In the mean time I've replaced the two offending characters with
ones that look similar. It means the example output is technically
incorrect, but at least it's readable).&lt;/p&gt;


</content>
    <author>
      <name>Moritz Lenz</name>
    </author>
    <id>http://perlgeek.de/blog-en/perl-6/2017-017-living-on-the-bleading-edge.html</id>
    <published>2017-06-24T22:00:01+01:00</published>
    <updated>2017-06-24T22:00:01+01:00</updated>
  </entry>
  <entry>
    <title>Rakudo Star: Past Present and Future</title>
    <link rel="alternate" type="text/html" href="https://blogs.perl.org/users/steve_mynott/2017/01/rakudo-star-past-present-and-future.html"/>
    <id>tag:blogs.perl.org,2017:/users/steve_mynott//2714.7874</id>

    <published>2017-01-02T14:07:31Z</published>
    <updated>2017-01-02T14:09:16Z</updated>

    <summary>At YAPC::EU 2010 in Pisa I received a business card with "Rakudo Star" and the date July 29, 2010 which was the date of the first release -- a week earlier with a countdown to 1200 UTC. I still have...</summary>
    <author>
        <name>Steve Mynott</name>
        
    </author>
    
    <category term="perl6" label="perl6" scheme="http://www.sixapart.com/ns/types#tag"/>
    
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/steve_mynott/">
        <![CDATA[<p>At YAPC::EU 2010 in Pisa I received a business card with "Rakudo Star" and the<br />
date July 29, 2010 which was the date of the first release -- a week earlier<br />
with a countdown to 1200 UTC. I still have mine, although it has a tea stain<br />
on it and I refreshed my memory over the holidays by listening again to Patrick<br />
Michaud speaking about the launch of Rakudo Star (R*):</p>

<p><a href="https://www.youtube.com/watch?v=MVb6m345J-Q">https://www.youtube.com/watch?v=MVb6m345J-Q<br />
</a></p>

<p>R* was originally intended as first of a number of distribution releases (as<br />
opposed to a compiler release) -- useable for early adopters but not initially production<br />
Quality. Other names had been considered at the time like Rakudo Beta (rejected as<br />
sounding like "don't use this"!) and amusingly Rakudo Adventure Edition.<br />
Finally it became Rakudo Whatever and Rakudo Star (since * means "whatever"!).</p>

<p>Well over 6 years later and we never did come up with a better name although there<br />
was at least one IRC conversation about it and perhaps "Rakudo Star" is too<br />
well established as a brand at this point anyway. R* is the Rakudo compiler, the main docs, a module installer, some modules and some further docs.</p>

<p>However, one radical change is happening soon and that is a move from panda to<br />
zef as the module installer.  Panda has served us well for many years but zef is<br />
both more featureful and more actively maintained.  Zef can also install Perl<br />
6 modules off CPAN although the CPAN-side support is in its early days.  There<br />
is a zef branch (pull requests welcome!) and a tarball at:</p>

<p><a href="http://pl6anet.org/drop/rakudo-star-2016.12.zef-beta2.tar.gz">http://pl6anet.org/drop/rakudo-star-2016.12.zef-beta2.tar.gz<br />
</a></p>

<p>Panda has been patched to warn that it will be removed and to advise the use of<br />
zef.  Of course  anyone who really wants to use panda can reinstall it using zef<br />
anyway.</p>

<p>The modules inside R* haven't changed much in a while. I am considering adding<br />
DateTime::Format (shown by ecosystem stats to be widely used) and<br />
HTTP::UserAgent (probably the best pure perl6 web client library right now).<br />
Maybe some modules should also be removed (although this tends to be more<br />
controversial!).  I am also wondering about OpenSSL support (if the library is<br />
available).</p>

<p>p6doc needs some more love as a command line utility since most of the focus<br />
has been on the website docs and in fact some of these changes have impacted<br />
adversely on command line use, eg. under Windows cmd.exe "perl 6" is no longer<br />
correctly displayed by p6doc. I wonder if the website generation code should be<br />
decoupled from the pure docs and p6doc command line (since R* has to ship any<br />
new modules used by the website).  p6doc also needs a better and faster search<br />
(using sqlite?). R* also ships some tutorial docs including a PDF generated from perl6intro.com.<br />
We only ship the English one and localisation to other languages could be<br />
useful.</p>

<p>Currently R* is released roughly every three months (unless significant<br />
breakage leads to a bug fix release). Problems tend to happen with the<br />
less widely used systems (Windows and the various BSDs) and also with the<br />
module installers and some modules. R* is useful in spotting these issues<br />
missed by roast. Rakudo itself is still in rapid development.  At some point a less frequently<br />
updated distribution (Star LTS or MTS?) will be needed for Linux distribution<br />
packagers and those using R* in production).  There are also some question<br />
marks over support for different language versions (6.c and 6.d).</p>

<p>Above all what R* (and Rakudo Perl 6 in general) needs is more people spending<br />
more time working on it! JDFI! Hopefully this blog post might<br />
encourage more people to get involved with github pull requests. </p>

<p><a href="https://github.com/rakudo/star">https://github.com/rakudo/star<br />
</a><br />
Feedback, too, in the comments below is actively encouraged.</p>

<p><br />
</p>]]>
        
    </content>
</entry>
  <entry>
    <title>Rakudo Star 2016.11 Release Candidate </title>
    <link rel="alternate" type="text/html" href="https://blogs.perl.org/users/steve_mynott/2016/11/rakudo-star-201611-release-candidate.html"/>
    <id>tag:blogs.perl.org,2016:/users/steve_mynott//2714.7796</id>

    <published>2016-11-20T14:01:22Z</published>
    <updated>2016-11-20T14:32:45Z</updated>

    <summary>There is a Release Candidate for Rakudo Star 2016.11 (currently RC2) available at http://pl6anet.org/drop/ This includes binary installers for Windows and Mac. Usually Star is released about every three months but last month's release didn't include a Windows installer so...</summary>
    <author>
        <name>Steve Mynott</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/steve_mynott/">
        <![CDATA[<p>There is a Release Candidate for Rakudo Star 2016.11 (currently RC2) available at</p>

<p><a href="http://pl6anet.org/drop/">http://pl6anet.org/drop/<br />
</a><br />
This includes binary installers for Windows and Mac.</p>

<p>Usually Star is released about every three months but last month's release didn't include a Windows installer so there is another release.</p>

<p>I'm hoping to release the final version next weekend and would be grateful if people could try this out on as many systems as possible. </p>

<p>Any feedback email steve *dot* mynott *at* gmail *dot* com</p>

<p>Full draft announce at</p>

<p><a href="https://github.com/rakudo/star/blob/master/docs/announce/2016.11.md">https://github.com/rakudo/star/blob/master/docs/announce/2016.11.md<br />
</a></p>]]>
        
    </content>
</entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-6738596093630756207.post-5830469984224402510</id>
    <published>2016-10-16T06:10:00.000-07:00</published>
    <updated>2016-10-19T12:39:34.779-07:00</updated>
    <title type="text">Rakudo Star 2016.10 Release Candidate</title>
    <content type="html">There is a Release Candidate for Rakudo Star 2016.10 (currently RC0) available at&lt;br /&gt;
&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="s1"&gt;&lt;a href="http://pl6anet.org/drop/"&gt;http://pl6anet.org/drop/&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
This should be quite a bit faster than previous releases and work better on OpenBSD/FreeBSD than the previous release.&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
It also features "prove6" which is now used by Panda -- removing a run-time dependency on Perl 5. Although it still needs Perl 5 to build.&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
I'm hoping to release the final version next weekend (Oct 21st) and would be grateful if people could try this out on as many systems as possible (eg. exotic systems like Solaris-like ones and Windows!)&amp;nbsp;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
Full draft announce at&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;a href="https://www.blogger.com/goog_1218437599"&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;a href="https://github.com/rakudo/star/blob/master/docs/announce/2016.10.md"&gt;https://github.com/rakudo/star/blob/master/docs/announce/2016.10.md&lt;/a&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
Note compiling under Windows is possible using the gcc which comes with Strawberry Perl and gmake running under cmd.exe. &amp;nbsp;Further instructions will be added (thanks to Christopher for feedback).&lt;br /&gt;
&lt;br /&gt;
Any feedback email steve *underscore* mynott *at* gmail *dot* com&lt;/div&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="http://stevemynott.blogspot.com/feeds/5830469984224402510/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://stevemynott.blogspot.com/2016/10/there-is-release-candidate-for-rakudo.html#comment-form" title="2 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/5830469984224402510"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/5830469984224402510"/>
    <link rel="alternate" type="text/html" href="http://stevemynott.blogspot.com/2016/10/there-is-release-candidate-for-rakudo.html" title="Rakudo Star 2016.10 Release Candidate"/>
    <author>
      <name>Steve</name>
      <uri>http://www.blogger.com/profile/07436556027517196055</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>2</thr:total>
  </entry>
  <entry>
    <title>You Wouldn't BELIEVE what I saw at YAPC::EU!!!</title>
    <link rel="alternate" type="text/html" href="https://blogs.perl.org/users/steve_mynott/2016/08/you-wouldnt-believe-what-i-saw-at-yapceu.html"/>
    <id>tag:blogs.perl.org,2016:/users/steve_mynott//2714.7641</id>

    <published>2016-08-28T18:57:57Z</published>
    <updated>2016-08-28T19:00:22Z</updated>

    <summary>We turned up in Cluj via Wizz Air to probably one of the best pre YAPC parties ever located on three levels on the rooftop of Evozon‎’s plush city centre offices. We were well supplied with excellent wine, snacks and...</summary>
    <author>
        <name>Steve Mynott</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/steve_mynott/">
        <![CDATA[<p>We turned up in Cluj via Wizz Air to probably one of the best pre YAPC parties ever located on three levels on the rooftop of Evozon‎’s plush city centre offices. We were well supplied with excellent wine, snacks and the local Ursus beer and had many interesting conversations with old friends.  </p>

<p>On the first day Tux spoke about his Text::CSV modules for both Perl 5 and 6 on the first day and I did a short talk later in the day on benchmarking Perl 6.  Only Nicholas understood my trainspotter joke slide with the APT and Deltic! Sadly my talk clashed with Lee J talking about Git which I wanted to see so I await the youtube version!  Jeff G then spoke about Perl 6 and parsing languages such as JavaScript. Sadly I missed Leon T’s Perl 6 talk which I also plan on watching on youtube.  Tina M gave an excellent talk on writing command line tools. She also started the lightning talks with an evangelical talk about how tmux was better than screen. Geoffrey A spoke about configuring sudo to run restricted commands in one directory which seemed a useful technique to me. Dave C continued his conference tradition of dusting off his Perl Vogue cover and showing it again. The age of the image was emphasised by the amazingly young looking mst on it. And Stefan S ended with a call for Perl unification. </p>

<p>The main social event was in the courtyard of the main museum off the central square with free food and beer all evening and an impressive light show on the slightly crumbling facade. There were some strange chairs which resembled cardboard origami but proved more comfortable than they looked when I was finally able to sit in one.  The quality of the music improved as the evening progressed (or maybe the beer helped) I was amazed to see Perl Mongers actually dancing apparently inspired by the younger Cluj.pm members. </p>

<p>Day Two started with Sawyer’s State of the Velociraptor‎ which he had, sensibly, subcontracted to various leading lights of the Perl Monger community.  Sue S (former London.pm leader) was up first with a short and sweet description of London.pm. Todd R talked about Houston.pm. Aaron Crane spoke about the new improved friendlier p5p. Tina about Berlin.pm and the German Perl community site she had written back in the day.  This new format worked very well and it was obvious Perl Mongers groups could learn much from each other. Max M followed with a talk about using Perl and ElasticSearch to index websites and documents and Job about accessibility.</p>

<p>1505 had, from the perspective of London.pm, one of the most unfortunate scheduling clashes at YAPC::EU ever, with three titans of London.pm (all former leaders) battling for audience share. I should perhaps tread carefully here lest bias become apparent but the heavyweight Sue Spence was, perhaps treacherously, talking about Go in the big room and Dave Cross and Tom talking about Perl errors and HTML forms respectively in the other rooms.  This momentous event should be reproducible by playing all three talks together in separate windows once they are available.</p>

<p>Domm did a great talk on Postgres which made me keen to use this technology again. André W described how he got Perl 6 running on his Sailfish module phone while Larry did a good impression of a microphone stand. I missed most of Lance Wick’s talk but the bit I caught at the end made me eager to watch the whole thing.</p>

<p>Guinevere Nell gave a fascinating lightning talk about agent based economic modelling. Lauren Rosenfield spoke of porting (with permission) a “Python for CS” book to perl 6. Lukas Mai described his journey from Perl to Rust. Lee J talked about photography before Sue encouraged people to break the London.pm website.  Outside the talk rooms on their stall Liz and Wendy had some highly cool stuffed toy Camelia butterflies produced by the Beverly Hills Teddy Bear Company and some strange “Camel Balls” bubblegum. At the end of the day Sue cat herded many Mongers to eat at the Enigma Steampunk Bar in central Cluj with the cunning ploy of free beer money (recycled from the previous year’s Sherry money).</p>

<p>The third day started with Larry’s Keynote in which photographs of an incredible American house “Fallingwater” and Chinese characters (including “arse rice”) featured heavily. Sweth C gave a fast and very useful introduction to swift. Nicholas C then confused a room of people for an hour with a mixture of real Perl 5 and 6 and an alternative timeline compete with T shirts. The positive conclusion was that even if the past had been different the present isn’t likely to have been much better for the Perl language family than it is now! Tom spoke about Code Review and Sawyer about new features in Perl 5.24.  Later I heard Ilya talk about running Perl on his Raspberry PI Model B and increasing the speed of his application very significantly to compensate for its low speed! And we finished with lightning talks where we heard about the bug tracker OTRS (which was new to me), Job spoke about assistive tech and Nine asked us to ask our bosses for money for Perl development amongst several other talks.  We clapped a lot in thanks, since this was clearly a particularly well organised YAPC::EU (due to Amalia and her team!)  and left to eat pizza and fly away the next day.  Some stayed to visit a salt mine (which looked most impressive from the pictures!) and some stayed longer due to Lufthansa cancelling their flights back!</p>

<p><br />
</p>]]>
        
    </content>
</entry>
  <entry>
    <title>German Perl Workshop 2016</title>
    <link rel="alternate" type="text/html" href="https://blogs.perl.org/users/steve_mynott/2016/03/german-perl-workshop-2016.html"/>
    <id>tag:blogs.perl.org,2016:/users/steve_mynott//2714.7354</id>

    <published>2016-03-15T15:36:12Z</published>
    <updated>2016-03-15T15:53:38Z</updated>

    <summary>The meeting first night was in a large beer bar in the centre of Nuremberg. We went back to the Best Western to find a certain exPumpkin already resident in the bar. Despite several of the well named Bitburgers we...</summary>
    <author>
        <name>Steve Mynott</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/steve_mynott/">
        <![CDATA[<p>The meeting first night was in a large beer bar in the centre of Nuremberg. <br />
We went back to the Best Western to find a certain exPumpkin already resident in the bar.<br />
Despite several of the well named Bitburgers we managed to arrive at the<br />
conference venue on time the following morning. Since my knowledge of German was<br />
limited to a C grade 'O' Level last century my review talks will be mostly<br />
limited to English talks.  Apologies in advance to those giving German talks<br />
(not unreasonable considering the country). Hopefully other blog posts will<br />
cover these.  </p>

<p>Masak spoke about the dialectic between planning (like physics) and chaos (like<br />
biology) in software development.  </p>

<p><a href="http://masak.org/carl/gpw-2016-domain-modeling/talk.pdf">http://masak.org/carl/gpw-2016-domain-modeling/talk.pdf</a></p>

<p>Tobias gave a good beginners guide to Perl 6 in German and I was able to follow<br />
most of the slides since I knew more Perl 6 than German and even learnt a thing<br />
or two.</p>

<p>After lunch Stefan told us he was dancing around drunk and naked on the turn of<br />
the 2000s and also about communication between Perl 6 and Perl 5 and back again<br />
via his modules Inline::Perl5 (from Perl 6) -- the most important take away<br />
being that "use Foo::Bar:from&lt;Perl5&gt;" can be used from Perl 6 and "use<br />
Inline::Perl6" from Perl 5.  The modules built bridges like those built in the<br />
old school computer game "Lemmings".<br />
<a href="http://niner.name/talks/Perl%205%20and%20Perl%206%20-%20a%20great%20team/Perl%205%20and%20Perl%206%20-%20a%20great%20team.odp"><br />
http://niner.name/talks/Perl%205%20and%20Perl%206%20-%20a%20great%20team/Perl%205%20and%20Perl%206%20-%20a%20great%20team.odp</a></p>

<p>Max told us (in German) about his Dancer::SearchApp search<br />
engine which has based on Elastic Search but I was able to follow along on the<br />
English version of his slides on the web.  </p>

<p><a href="http://corion.net/talks/dancer-searchapp/dancer-searchapp.en.html">http://corion.net/talks/dancer-searchapp/dancer-searchapp.en.html</a></p>

<p>Sue got excited about this.  Tina showed us some slides in Vim and her module<br />
to add command line tab completion to script arguments using zsh and bash.  I<br />
wondered whether some of her code could be repurposed to add fish shell man<br />
page parsing autocompletion to zsh.  She also had a good lightening talk about<br />
Ingy's command line utility for github.<br />
<a href="https://github.com/perlpunk/myslides/tree/master/app-spec"><br />
https://github.com/perlpunk/myslides/tree/master/app-spec</a></p>

<p>Second day started early with Moritz talking about Continuous Delivery which<br />
could mean just delivering to a staging server. He was writing a book about it<br />
at deploybook.com with slides at:</p>

<p><a href="https://deploybook.com/talks/gpw2016-continuous-delivery.pdf">https://deploybook.com/talks/gpw2016-continuous-delivery.pdf</a></p>

<p>Salve wanted us to write elegant code as a reply to the Perl Jam guy at CCC in<br />
a self confessed "rant".</p>

<p>Sawyer described writing Ref::Util to optimise things like "ref $foo" in a<br />
Hardcore Perl 5 XS/Core talk and Masak told us about his little 007 language<br />
written in Perl 6 as a proof of concept playroom for future Perl 6 extended<br />
macro support and demonstrated code written over lunch in support of this.</p>

<p><a href="http://masak.org/carl/gpw-2016-big-hairy-yaks/talk.pdf">http://masak.org/carl/gpw-2016-big-hairy-yaks/talk.pdf</a></p>

<p>Stefan gave a great talk about CURLI and explained the complexity of what was<br />
intended.</p>

<p><a href="http://niner.name/talks/A%20look%20behind%20the%20curtains%20-%20module%20loading%20in%20Perl%206/Module%20loading%20in%20Perl%206.pdf">http://niner.name/talks/A%20look%20behind%20the%20curtains%20-%20module%20loading%20in%20Perl%206/Module%20loading%20in%20Perl%206.pdf</a></p>

<p>I gave my talk  on "Simple Perl 6 Fractals and Concurrency" on Friday.  It<br />
started badly with AV issues my side but seemed well received. It was useful<br />
speaking with people about it and I managed to speed things up *after* the talk<br />
and I should have new material for a 2.0 version.  </p>

<p>There were very good talks on extracting data from PDFs and writing JSON apis.<br />
<a href="https://github.com/mickeyn/PONAPI"><br />
https://github.com/mickeyn/PONAPI </a></p>

<p>looked very interesting and would have saved me much coding at a recent job.</p>

<p>There were some great lightening talks at th end of the day. Sawyer wanted<br />
people to have English slides and gave his talk in Hebrew to stress this.<br />
Things ended Friday night with great food and beer in a local bar.<br />
</p>]]>
        
    </content>
</entry>
  <entry>
    <title>FOSDEM 2016</title>
    <link rel="alternate" type="text/html" href="https://blogs.perl.org/users/steve_mynott/2016/02/fosdem-2016.html"/>
    <id>tag:blogs.perl.org,2016:/users/steve_mynott//2714.7281</id>

    <published>2016-02-02T19:33:44Z</published>
    <updated>2016-02-02T19:36:48Z</updated>

    <summary>To me It seemed a particularly good FOSDEM for both for Perl5/6 and other talks although very crowded as usual and I didn't see the usual *BSD or Tor stalls. I was stuck by the statistic that there were about...</summary>
    <author>
        <name>Steve Mynott</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="https://blogs.perl.org/users/steve_mynott/">
        <![CDATA[<p>To me It seemed a particularly good FOSDEM for both for Perl5/6 and<br />
other talks although very crowded as usual and I didn't see the usual<br />
*BSD or Tor stalls.  I was stuck by the statistic that there were<br />
about 500 speakers from many thousands of people so of the order of<br />
one speaker per tens of attendees which is very high.</p>

<p>Videos are already starting to appear at</p>

<p><a href="http://video.fosdem.org/2016/">http://video.fosdem.org/2016/</a></p>

<p>On Saturday I started with Poettering and systemd which was a keynote<br />
and perhaps a little disappointing since he usually is a better<br />
speaker and the audio was a little indistinct.  systemd had won being<br />
used by all distros except gentoo and slackware. They were now working<br />
on a dns resolver component which supported DNSSEC although in<br />
practice validating signed zone files would slow down browsing and<br />
currently only 2% of websites had it activated.  He didn't mention<br />
strong criticisms of its security by crypto experts such as DJB.</p>

<p>The most amusing talk was Stark's retro running of Postgres on<br />
NetBSD/VAX which exposed some obscure OS bugs and was livened up by a<br />
man in an impressive Postgres Elephant costume appearing.  We later<br />
spoke to Mr Elephant who said he was both blind and very hot at the<br />
time. I then went to the Microkernel room to hear about GNU/Hurd<br />
progress from Thibault since this room is usually "OPEN" and he's an<br />
excellent speaker.  I noticed even this obscure room was quite crowded<br />
as compared with previous years so I'd guess total attendees this year<br />
were high.  He stressed the advantages of running device drivers in<br />
userspace as allowing more user "freedom" to mount fs etc. without<br />
root and improving kernel stability since the drivers could crash and<br />
restart without bringing down the kernel.  In previous years he had<br />
talked of his DDE patches allowing linux 2.6 hardware drivers on Hurd<br />
and this year he was using the NetBSD Rump kernel under Hurd to add<br />
sound support with USB support promised.  His demo was RMS singing his<br />
song on his Hurd laptop.  The irony was he needed to use BSD code on a<br />
GNU/BSD/Hurd system to do it!  There had been some work on X86-64 Hurd<br />
but it wasn't there yet since he needed more help from the community.<br />
I then saw some lightening talks (actually 20 mins long) including a<br />
good one on C refactoring.</p>

<p>The Perl dinner on Saturday night featured the usual good food and<br />
conversation and the devroom was on Sunday.  Ovid spoke about Perl 6<br />
and its advantages (such as being able to perform maths on floats<br />
correctly). I had a python guy sitting next to me who admitted he had<br />
never been to a Perl talk before so that was a success in reaching<br />
someone new.  Will Braswell spoke next about his "Rperl" compiler<br />
which translated his own quite restricted subset (no regexps yet and<br />
no $_) of Perl 5 line by line into C++ in order to run some of the<br />
language shootups benchmarks (a graphical animation of planetary<br />
motion) at increased speed.  I'd not seen Will before and he was an<br />
excellent speaker who left me more impressed than I'd expected and I<br />
hope he gets to YAPC::EU in the summer.  I saw some non-Perl stuff<br />
next for variety including a good one on the Go debugger Delve which<br />
was aware of the go concurrency and could be used as a basic REPL.  I<br />
returned to Perl to see Bart explain some surprisingly simple X86-64<br />
assembly language to do addition and ROT13 which he interfaced with<br />
Perl 6 using NativeCall (although it stuck me that the<br />
 CPAN P5NCI module on Perl 5 would have also worked).  <br />
Again an excellent talk and a good start to the a<br />
run of some of the best Perl talks I'd ever seen. Stevan Little's talk<br />
was one of the his most amusing ever and perl wasn't really dead.<br />
Sawyer also did an excellent promotion of Perl 5 targeted at the<br />
people who maybe hadn't used it since the early 2000s explaining what<br />
had changed.  Liz finished with her autobiographical account of Perl<br />
development and some nice short Perl 6 examples.  We all ate again in<br />
the evening together my only regrets being I'd missed the odd talk or<br />
two (which I should be able to watch on video).</p>]]>
        
    </content>
</entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-6738596093630756207.post-1832060940683956756</id>
    <published>2016-01-09T13:32:00.002-08:00</published>
    <updated>2016-01-09T13:32:25.934-08:00</updated>
    <title type="text">FOSDEM 2016 Perl Dev Room Lineup</title>
    <content type="html">FOSDEM is a free two day conference in Brussels, Belgium on Jan 30th and 31st 2016.&lt;br /&gt;
&lt;br /&gt;
The FOSDEM 2016 schedule for the Perl Dev Room on the second day (the Sunday)&amp;nbsp; has now been announced at&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://fosdem.org/2016/schedule/track/perl/"&gt;https://fosdem.org/2016/schedule/track/perl/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
From a Perl 6 perspective it includes&amp;nbsp; Ovid's "&lt;i&gt;Perl 6 for those who hate Perl&lt;/i&gt;", Daisuke Maki on "&lt;i&gt;Crust --&amp;nbsp; Perl6 Port of Plack&lt;/i&gt;", Jeffrey Goff on &lt;i&gt;Perl 6 Grammars&lt;/i&gt;, Bart Wiegmans talks about AMD64 assembly language programming and MoarVM, Stevan Little's "&lt;i&gt;Perl is not dead,... it got better&lt;/i&gt;" and lastly Elizabeth Mattijsen finishes with "&lt;i&gt;Perl 6 -- The end of the beginning&lt;/i&gt;".</content>
    <link rel="replies" type="application/atom+xml" href="http://stevemynott.blogspot.com/feeds/1832060940683956756/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://stevemynott.blogspot.com/2016/01/fosdem-2016-perl-dev-room-lineup.html#comment-form" title="0 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/1832060940683956756"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/1832060940683956756"/>
    <link rel="alternate" type="text/html" href="http://stevemynott.blogspot.com/2016/01/fosdem-2016-perl-dev-room-lineup.html" title="FOSDEM 2016 Perl Dev Room Lineup"/>
    <author>
      <name>Steve</name>
      <uri>http://www.blogger.com/profile/07436556027517196055</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-9216314883714415579.post-4928207886018496826</id>
    <published>2015-10-09T07:04:00.003-07:00</published>
    <updated>2015-10-09T13:34:38.755-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="Perl6"/>
    <title type="text">Perl6 and CPAN:  MetaCPAN Status as of 2015-10-09</title>
    <content type="html">&lt;p&gt;MetaCPAN, like the rest of "CPAN", was built assuming the sole context of
Perl5.  Which is cool until we want to use it for Perl6 and avoid the
troubles associated with different namespaces, dist mgmt, etc...  To largely
avoid and more easily handle these issues for MetaCPAN it's been suggested
that we have separate instances.  The existing Perl5 instance only needs to
be changed to ignore Perl6 distributions.  There has already been some
breakage because it didn't ignore a Perl6 dist of mine which exists in the
Perl5 world:(  And the new Perl6 instance will do just the opposite and only
look at Perl6 distributions.&lt;/p&gt;

&lt;p&gt;In contrast, and relatedly, on CPAN we've designated a special spot for
Perl6 distributions in order to keep them separate from the Perl5 dists.
This reserved place is a Perl6 subdir in an author's dir
(/author/id/*/*/*/Perl6/).  Any dists in or under that spot on the fs will
be considered a Perl6 dist;  valid or invalid.  So this is where the Perl6
MetaCPAN will look and the Perl5 instance will not.&lt;/p&gt;

&lt;p&gt;Current development is being done on these temporary branches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;https://github.com/jdv/metacpan-web&lt;/li&gt;
&lt;li&gt;https://github.com/jdv/cpan-api&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the main dev instance is running on hack.p6c.org.  The web end is at
http://hack.p6c.org:5001 and the api is at http://hack.p6c.org:5000.&lt;/p&gt;

&lt;p&gt;So far the idea has been to iterate on the aforementioned branches and
instance until we have something that works sufficiently well.  At that
point we'll tidy up the branches and submit them for merging.  Shortly after
that time the hope is that we'll be able to stand up the official Perl6
instance.&lt;/p&gt;

&lt;p&gt;The list of requirements for being adequately cooked is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;track Perl6 CPAN dists and ignore Perl5 dists&lt;/li&gt;
&lt;li&gt;import a Perl6 distribution&lt;/li&gt;
&lt;li&gt;index a Perl6 distribution for search&lt;/li&gt;
&lt;li&gt;render pod6 documentation&lt;/li&gt;
&lt;li&gt;do Perl6 syntax highlighting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these have been hacked in and are at various degrees of completeness.
Next up is testing and fixing bugs until nothing major is left.  To that end
I've recently loaded up the dev instance with all the distributions from
modules.perl6.org.  The dist files were generated, very hackily, with
https://github.com/jdv/cpan-api/blob/master/test_p6_eco_to_p6_cpan.pl.  I
also just loaded them all under one user, mine, for simplicity.  That load
looks like it has problems of its own as well as revealing a bunch of
issues.  So in the coming days I hope to get that all sorted out.&lt;/p&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="http://jdv79.blogspot.com/feeds/4928207886018496826/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://jdv79.blogspot.com/2015/10/perl6-and-cpan-metacpan-status-as-of.html#comment-form" title="0 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9216314883714415579/posts/default/4928207886018496826"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9216314883714415579/posts/default/4928207886018496826"/>
    <link rel="alternate" type="text/html" href="http://jdv79.blogspot.com/2015/10/perl6-and-cpan-metacpan-status-as-of.html" title="Perl6 and CPAN:  MetaCPAN Status as of 2015-10-09"/>
    <author>
      <name>jdv</name>
      <uri>http://www.blogger.com/profile/13172179525194965590</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-9216314883714415579.post-4945461108379135079</id>
    <published>2015-10-08T13:31:00.000-07:00</published>
    <updated>2015-10-08T13:31:32.351-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="Perl6"/>
    <title type="text">Perl6 and CPAN</title>
    <content type="html">&lt;p&gt;In the Perl5 world, just in case anyone is unaware, CPAN is a major factor.  Its
basically the hub of the Perl5 world.&lt;/p&gt;

&lt;p&gt;What I am referring to here as CPAN is not just the mirrored collection of 32K+
distributions.  Its the ecosystem that's built up around that collection.  This
ecosystem has many parts, some more important than others depending on who you
talk to, but the most important parts to me are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the mirrored distribution collection - all the Perl5 modules in one place&lt;/li&gt;
&lt;li&gt;pause (pause.perl.org) - module upload and mgmt services&lt;/li&gt;
&lt;li&gt;metacpan (metacpan.org) - online search, docs, and other services&lt;/li&gt;
&lt;li&gt;cpan testers (http://cpantesters.org/) - CPAN smoking&lt;/li&gt;
&lt;li&gt;module installers - Perl5 has cpanm and others - Perl6 has panda and others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the 5 aspects of "CPAN" that I'd like to see happen for Perl6.  One
way to get that would be to write the whole thing from scratch in Perl6.  While
it may sound cool in some sort of dogfoody and/or bootstrappy kind of way to some,
it sounds like a lot of work to me and we're a bit strapped for developer
resources.  Another way would be to add support for Perl6 to the existing CPAN
bits.  The hope there being, primarily, that it'd be a lot less work.  The
latter approach is what I've been working on lately.  And if we want to refactor
ourselves off the Perl5 bits in the future we can take our time doing it;
later.&lt;/p&gt;

At this time we have:

&lt;ul&gt;
&lt;li&gt;basic pause support&lt;/li&gt;
&lt;li&gt;a metacpan prototype&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we can publish Perl6 distributions to CPAN and search that collection.  Well,
sort of on that last bit.  The metacpan prototype instance is not currently
tracking CPAN.  Its actually been loaded up with Perl6 distributions from the
Perl6 module ecosystem (modules.perl6.org) for testing.  But hopefully soon
we'll have an official Perl6 metacpan instance, separate from the Perl5
instance, that will track CPAN's Perl6 content as it should.&lt;/p&gt;

What we need next is:

&lt;ul&gt;
&lt;li&gt;completion of basic metacpan Perl6 support&lt;/li&gt;
&lt;li&gt;at least one Perl6 module installer to support CPAN (probably panda)&lt;/li&gt;
&lt;li&gt;Perl6 integration with cpan testers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If anyone is interested in working on any of this stuff please stop by #perl6 on
freenode.  If nobody else is able to help you I'll (jdv79) do my best.&lt;/p&gt;</content>
    <link rel="replies" type="application/atom+xml" href="http://jdv79.blogspot.com/feeds/4945461108379135079/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://jdv79.blogspot.com/2015/10/perl6-and-cpan.html#comment-form" title="3 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9216314883714415579/posts/default/4945461108379135079"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9216314883714415579/posts/default/4945461108379135079"/>
    <link rel="alternate" type="text/html" href="http://jdv79.blogspot.com/2015/10/perl6-and-cpan.html" title="Perl6 and CPAN"/>
    <author>
      <name>jdv</name>
      <uri>http://www.blogger.com/profile/13172179525194965590</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>3</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-6738596093630756207.post-6257780619770289688</id>
    <published>2015-09-11T09:43:00.000-07:00</published>
    <updated>2015-09-14T05:14:10.767-07:00</updated>
    <title type="text"/>
    <content type="html">&lt;h2&gt;
A Little GLRer (revision 1)&lt;/h2&gt;
The GLR (Great List Refactor) radically changed the way lists worked in Rakudo (an implementation of Perl). &lt;br /&gt;
&lt;br /&gt;
This blog post is a list of some one-liners to show differences between the old (pre-glr) rakudo and the new (glr) rakudo intended to aid understanding and porting of modules.&lt;br /&gt;
&lt;br /&gt;
Note this was done for self-education and may contain errors or things which may change.&amp;nbsp; 
&lt;p&gt;
Thanks to those on Freenode IRC/perl6 for help.
&lt;p&gt;
Further corrections and expansions welcome either on iRC via pull request to &lt;a href="https://github.com/stmuk/glr-html"&gt;https://github.com/stmuk/glr-html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

&lt;!-- I really need to generate this dynamically STM --&gt;

&lt;table border="1" cellpadding="2" cellspacing="2" width="100%"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;br&gt; &lt;/td&gt; &lt;td valign="top"&gt;&lt;b&gt;&amp;nbsp;pre&amp;nbsp; GLR&lt;b&gt;&lt;br&gt; &lt;/td&gt; &lt;td valign="top"&gt;&lt;b&gt;GLR&lt;/b&gt;&lt;br&gt; &lt;/td&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; LIST IS NOW PARCEL &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; say (1,2,3).WHAT&lt;/pre&gt;
                &lt;pre&gt;(Parcel)&lt;/pre&gt;
            &lt;/td&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; say (1,2,3).WHAT&lt;/pre&gt;
                &lt;pre&gt;(List)&lt;/pre&gt;
            &lt;/td&gt;

            &lt;/tt&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; LACK OF IMPLICIT LIST FLATTENING &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; my @array = 1,(2,3),4&lt;/pre&gt;
                &lt;pre&gt;1 2 3 4&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; @array.elems&lt;/pre&gt;
                &lt;pre&gt;4&lt;/pre&gt;
            &lt;/td&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;my @array = 1,(2,3),4&lt;/pre&gt;
                &lt;pre&gt;[1 (2 3) 4]&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; @array.elems&lt;/pre&gt;
                &lt;pre&gt;3&lt;/pre&gt;
                &lt;h4&gt;to flatten&lt;/h4&gt;
                &lt;pre&gt;&amp;gt; my @list := 1, [2, 3], 4&lt;/pre&gt;
                &lt;pre&gt;(1 [2 3] 4)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd @list.flat.list&lt;/pre&gt;
                &lt;pre&gt;(1, 2, 3, 4)&lt;/pre&gt;
                &lt;h4&gt;or&lt;/h4&gt;
                &lt;pre&gt;&amp;gt; my @array = (1,(2,3),4).flat&lt;/pre&gt;
                &lt;pre&gt;[1 2 3 4]&lt;/pre&gt;
                &lt;h4&gt;or more complex structures (jnthn++)&lt;/h4&gt;
                &lt;pre&gt;say gather [[[[["a", "b"], "c"], "a"], "d"], "e"].deepmap(*.take)&lt;/pre&gt;


            &lt;/td&gt;

            &lt;/tt&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; .lol METHOD REMOVED &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; dd (1,2,3).lol&lt;/pre&gt;
                &lt;pre&gt;(1; 2; 3)&lt;/pre&gt;
            &lt;/td&gt;

            &lt;td valign="top"&gt;
            &lt;/td&gt;

            &lt;/tt&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; SINGLE ARG RULE &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; dd (1,)&lt;/pre&gt;
                &lt;pre&gt;(1,)&lt;/pre&gt;
                &lt;pre&gt;&gt; dd [1,]&lt;/pre&gt;
                &lt;pre&gt;$ = [1]&lt;/pre&gt;
                &lt;pre&gt;&gt; dd [[1,]]&lt;/pre&gt;
                &lt;pre&gt;$ = [[1]]&lt;/pre&gt;


            &lt;/td&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; dd (1,)&lt;/pre&gt;
                &lt;pre&gt;(1)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd [1,]&lt;/pre&gt;
                &lt;pre&gt;[1]&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd [[1],]&lt;/pre&gt;
                &lt;pre&gt;[[1],]&lt;/pre&gt;
            &lt;/td&gt;
            &lt;/tt&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; LIST NOW IMMUTABLE &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; my @array = 1,2,3&lt;/pre&gt;
                &lt;pre&gt;1 2 3&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; @array.shift&lt;/pre&gt;
                &lt;pre&gt;1&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd @array&lt;/pre&gt;
                &lt;pre&gt;@array = [2, 3]&lt;&gt;&lt;/pre&gt;

            &lt;/td&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; my @list := 1,2,3&lt;/pre&gt;
                &lt;pre&gt;(1 2 3)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; @list.shift&lt;/pre&gt;
                &lt;pre&gt;Method 'shift' not found for invocant of class 'List'&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; @list[0]&lt;/pre&gt;
                &lt;pre&gt;1&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd @list&lt;/pre&gt;
                &lt;pre&gt;(1, 2, 3)&lt;/pre&gt;
            &lt;/td&gt;

            &lt;/tt&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; ARRAY IS  MUTABLE AND A SUBCLASS OF LIST &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;

            &lt;/td&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; my @array = 1,2,3&lt;/pre&gt;
                &lt;pre&gt;[1 2 3]&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; @array[0]=0&lt;/pre&gt;
                &lt;pre&gt;0&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd @array&lt;/pre&gt;
                &lt;pre&gt;@array = [0, 2, 3]&lt;/pre&gt;
                &lt;pre&gt;&amp;gt;say (Array).^mro&lt;/pre&gt;
                &lt;pre&gt;((Array) (List) (Cool) (Any) (Mu))&lt;/pre&gt;
            &lt;/td&gt;

            &lt;/tt&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; SLIP SUBCLASS OF LIST &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;

            &lt;/td&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; my @a = 1, (2, 3).Slip, 4&lt;/pre&gt;
                &lt;pre&gt;[1 2 3 4]&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; my $slip = slip(2,3)&lt;/pre&gt;
                &lt;pre&gt;(2 3)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd $slip&lt;/pre&gt;
                &lt;pre&gt;Slip $slip = $(2, 3)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; my @array = 1,$slip,4&lt;/pre&gt;
                &lt;pre&gt;[1 2 3 4]&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; (1,$(2,3),4)&lt;/pre&gt;
                &lt;pre&gt;(1 (2 3) 4)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; (1,|(2,3),4)&lt;/pre&gt;
                &lt;pre&gt;(1 2 3 4)&lt;/pre&gt;

            &lt;/td&gt;

            &lt;/tt&gt;
        &lt;/tr&gt;

        &lt;tr&gt;
            &lt;td valign="top"&gt;&lt;b&gt; SEQUENCE &lt;/b&gt; &lt;/td&gt;
            &lt;tt&gt;

            &lt;td valign="top"&gt;

            &lt;/td&gt;

            &lt;td valign="top"&gt;
                &lt;pre&gt;&amp;gt; my $grep = (1..4).grep(*&gt;2); dd $grep&gt;&gt;.Int;&lt;/pre&gt;
                &lt;pre&gt;(3, 4)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd $grep&gt;&gt;.Int;&lt;/pre&gt;
                &lt;pre&gt;This Seq has already been iterated, and its values consumed&lt;/pre&gt;
                &lt;pre&gt;in block &lt;unit&gt; at &lt;unknown file&gt;:1&lt;/pre&gt;
                &lt;h4&gt;prevent consumption&lt;/h4&gt;
                &lt;pre&gt;&amp;gt; my $grep = (1..4).grep(*&gt;2); my $cache=$grep.cache&lt;/pre&gt;
                &lt;pre&gt;(3 4)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; say $cache&gt;&gt;.Int&lt;/pre&gt;
                &lt;pre&gt;(3 4)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; say $cache&gt;&gt;.Int&lt;/pre&gt;
                &lt;pre&gt;(3 4)&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; my @array = 1,(2,3),4&lt;/pre&gt;
                &lt;pre&gt;[1 (2 3) 4]&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd @array.flat&lt;/pre&gt;
                &lt;pre&gt;(1, $(2, 3), 4).Seq&lt;/pre&gt;
                &lt;pre&gt;&amp;gt; dd @array.flat.list&lt;/pre&gt;
                &lt;pre&gt;(1, $(2, 3), 4)&lt;/pre&gt;
            &lt;/td&gt;

            &lt;/tt&gt;
        &lt;/tr&gt;

    &lt;/tbody&gt;
&lt;/table&gt;
</content>
    <link rel="replies" type="application/atom+xml" href="http://stevemynott.blogspot.com/feeds/6257780619770289688/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://stevemynott.blogspot.com/2015/09/a-little-glrer-revision-1-glr-great.html#comment-form" title="0 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/6257780619770289688"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/6257780619770289688"/>
    <link rel="alternate" type="text/html" href="http://stevemynott.blogspot.com/2015/09/a-little-glrer-revision-1-glr-great.html" title=""/>
    <author>
      <name>Steve</name>
      <uri>http://www.blogger.com/profile/07436556027517196055</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>0</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-6738596093630756207.post-8857616217934041522</id>
    <published>2015-09-05T08:42:00.001-07:00</published>
    <updated>2015-09-05T09:11:41.252-07:00</updated>
    <title type="text">YAPC::EU 2015</title>
    <content type="html">We came down to Granada on Tuesday night and (after missing the pre-conference meeting with its free pizza) made our way to the Amsterdam Bar with its massive selection of bottled import beers and rather bizarre nut and soft sweets tapas.&lt;br /&gt;
&lt;br /&gt;
Wednesday morning we made our way to the venue.&amp;nbsp; The conference topic was Art and Engineering and the venue a particularly arty looking university science building with a large Foucault pendulum inside and "Bombes de Vapor" (steam engines and the like) outside.&amp;nbsp; The Arabic art influenced T shirts were the most stylish since the Pisa ones and the seats in the main hall were the most comfortable YAPC seats ever.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQQa3jJBh5fOv3kJ7ohni8p3TdByDun4oRR6T2NQRZfZoD5UznBp1ROb4ZyaowI-VnnHzlJG8qlGlWsm7bdFDJY0UmALwYyGlW_LZtmvJWI565NrGC4MuX0BV86R0kYBE8FyxqPUX1mf8/s1600/IMG_0334.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQQa3jJBh5fOv3kJ7ohni8p3TdByDun4oRR6T2NQRZfZoD5UznBp1ROb4ZyaowI-VnnHzlJG8qlGlWsm7bdFDJY0UmALwYyGlW_LZtmvJWI565NrGC4MuX0BV86R0kYBE8FyxqPUX1mf8/s320/IMG_0334.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
I first saw Leon Timmermans gave some good advice about how to contribute to Perl 5 core even if you didn't know the odd C89 plus macros language in which it was written.&amp;nbsp; It was followed by Bart (brrt) Wiegmans speaking about the Just In Time (JIT) compiler for MoarVM -- perl6's main VM -- in a quite high level talk so we were spared the scary details (which I later noticed included s-expressions).&amp;nbsp; Kang-min (gugod) Liu spoke about Booking's search engine which he couldn't show us and how he indexed his email (which he could). &lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://github.com/gugod/Mailsheep"&gt;https://github.com/gugod/Mailsheep&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
The main conference dinner of tapas was that evening around the pool of a four star hotel with constant glass refills.&amp;nbsp; Thankfully noone fell in.&amp;nbsp; More sadly we learnt Jeff Goff had been injured earlier and was in hospital.&lt;br /&gt;
&lt;br /&gt;
Next day started with Sawyer X's State of the [Art] Velociraptor which was upbeat and positive stressing the benefits of community.&amp;nbsp; Upasana spoke about Moose meta objects and Leonerd bravely fought AV issues to speak about how perl5 sort of resembled scheme a little bit.&amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://t.co/9KeXNzSSlJ"&gt;https://t.co/9KeXNzSSlJ&lt;/a&gt; &lt;br /&gt;
&lt;br /&gt;
At the end of day Xavier Noria, currently a ruby programmer, spoke about how much he missed Perl since many things (like docs) were better.&lt;br /&gt;
&lt;br /&gt;
Next day I got up at silly o'clock to hear Art School dropout Stevan Little compare his former subject with programming with some interesting details about painting techniques.&amp;nbsp; Kerstin Puschke talked about RabbitMQ including some live code examples using Perl 5.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://speakerdeck.com/titanoboa/decouple-all-the-things-asynchronous-messaging-keeps-it-simple"&gt;https://speakerdeck.com/titanoboa/decouple-all-the-things-asynchronous-messaging-keeps-it-simple&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBjVe9P7sSjOEr-gt62sEroLujTbWNC3nqQJXmRD83N-EYlqrNzXNpA6Ox-J57xx51mtESuujpee9L_IbFcGBfTCT6gllNEqSV6pf1ViA_RiZbsUaMTC0NP_3Cww0BUqhiWh4eCHhswu4/s1600/IMG_0320.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBjVe9P7sSjOEr-gt62sEroLujTbWNC3nqQJXmRD83N-EYlqrNzXNpA6Ox-J57xx51mtESuujpee9L_IbFcGBfTCT6gllNEqSV6pf1ViA_RiZbsUaMTC0NP_3Cww0BUqhiWh4eCHhswu4/s320/IMG_0320.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Domm told us about his image uploading Perl 6 script&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://domm.plix.at/talks/2015_granada_potd"&gt;http://domm.plix.at/talks/2015_granada_potd&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
which uploaded pics to twitter including one of his audience.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://domm.plix.at/potd/2015-09-04.html"&gt;http://domm.plix.at/potd/2015-09-04.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Gabor talked us through a minimal port of Dancer to Perl 6 called "Bailador" (which is part of Rakudo Star).&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://perl6maven.com/bailador-app-in-a-module"&gt;http://perl6maven.com/bailador-app-in-a-module&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
perl6maven.com actually uses perl6 in production!&lt;br /&gt;
&lt;br /&gt;
Herbert Breunung spoke about Functional Perl 6 using a particularly garish slide deck.&amp;nbsp; John Lightsey did a line by line audit of an old version of Module::Signature to point out some security issues.&amp;nbsp; Liz did Jonathan's Parallelism, Concurrency, and Asynchrony in Perl 6 since the original author sadly couldn't make it.&amp;nbsp; At least one thing had changed in the week since I last heard the talk!&lt;br /&gt;
&lt;br /&gt;
Finally a long haired Larry compared Perl 5 and 6 with Tolkien's Hobbit and Lord of the Rings respectively&amp;nbsp; and sang a bit. Two out of the three big ticket items for Perl 6.0 were done and things were looking good for a Long Expected Christmas Party.&amp;nbsp; This was a truly great keynote and went down a storm.&lt;br /&gt;
&lt;br /&gt;
Some of the final lightening talks were particularly good with one even given in rapid Japanese.&amp;nbsp; To finish off Friday night Sue organised a "Sherry Tasting" visit to a local tapas restaurant which also included much consumption of the local beer Alhambra 1925.&amp;nbsp; A large number of mongers turned up to effectively take over the whole place.&amp;nbsp; Some also stayed up all night playing card games </content>
    <link rel="replies" type="application/atom+xml" href="http://stevemynott.blogspot.com/feeds/8857616217934041522/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://stevemynott.blogspot.com/2015/09/we-came-down-to-granada-on-tuesday.html#comment-form" title="0 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/8857616217934041522"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/8857616217934041522"/>
    <link rel="alternate" type="text/html" href="http://stevemynott.blogspot.com/2015/09/we-came-down-to-granada-on-tuesday.html" title="YAPC::EU 2015"/>
    <author>
      <name>Steve</name>
      <uri>http://www.blogger.com/profile/07436556027517196055</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQQa3jJBh5fOv3kJ7ohni8p3TdByDun4oRR6T2NQRZfZoD5UznBp1ROb4ZyaowI-VnnHzlJG8qlGlWsm7bdFDJY0UmALwYyGlW_LZtmvJWI565NrGC4MuX0BV86R0kYBE8FyxqPUX1mf8/s72-c/IMG_0334.jpg" height="72" width="72"/>
    <thr:total>0</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-6738596093630756207.post-7122244262294722688</id>
    <published>2015-08-14T07:35:00.002-07:00</published>
    <updated>2015-08-14T07:35:32.986-07:00</updated>
    <title type="text">Perl6 Grammars for Beginners Talk</title>
    <content type="html">I gave a beginners level talk about Perl6 grammars to a meeting of London Perlmongers on Aug 13th talking about &lt;b&gt;App::p6tags (&lt;/b&gt;Generate editor tags for perl6).
    &lt;br /&gt;



    &lt;span class="edit-link js-details-target"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;a href="https://github.com/stmuk/p6-app-p6tags"&gt;https://github.com/stmuk/p6-app-p6tags&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sides are at&lt;br /&gt;
&lt;a href="https://drive.google.com/file/d/0B731WtD7iMvMbThKOEszellTTjA/view?usp=sharing"&gt;https://drive.google.com/file/d/0B731WtD7iMvMbThKOEszellTTjA/view?usp=sharing&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
And video on youtube. &lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/BQfP5o_0YzY/0.jpg" src="https://www.youtube.com/embed/BQfP5o_0YzY?feature=player_embedded" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content>
    <link rel="replies" type="application/atom+xml" href="http://stevemynott.blogspot.com/feeds/7122244262294722688/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://stevemynott.blogspot.com/2015/08/perl6-grammars-for-beginners-talk.html#comment-form" title="0 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/7122244262294722688"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6738596093630756207/posts/default/7122244262294722688"/>
    <link rel="alternate" type="text/html" href="http://stevemynott.blogspot.com/2015/08/perl6-grammars-for-beginners-talk.html" title="Perl6 Grammars for Beginners Talk"/>
    <author>
      <name>Steve</name>
      <uri>http://www.blogger.com/profile/07436556027517196055</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/BQfP5o_0YzY/default.jpg" height="72" width="72"/>
    <thr:total>0</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-1163079349106481731.post-5454750255157559759</id>
    <published>2015-05-03T19:57:00.000-07:00</published>
    <updated>2015-06-03T01:01:30.124-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="php6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="php7"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="programming"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="python3"/>
    <title type="text">Three Tales of Second System Syndrome</title>
    <content type="html">&lt;br /&gt;
In the last decade, three major scripting languages embarked on project to produce a major revision to each language: Perl 6, Python 3, and PHP 6. Despite surface similarities, such as the problem of Unicode support, each language ended up on a radically different track.&lt;br /&gt;
&lt;br /&gt;
With the Perl 6.0.0 release officially coming this year, it's a good time to reflect on how we got to this point, and to start thinking about what comes after the release.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 id="php-6"&gt;
PHP 6&lt;/h2&gt;
So -- and I can't believe I'm writing this -- let's see if we can learn something from PHP. Andi Gutmans, who is now the CEO of Zend Technologies, &lt;a href="http://www.itjungle.com/tlb/tlb021208-story09.html"&gt;gave an interview&lt;/a&gt; back in February 2008. In it, he said,
&lt;br /&gt;
&lt;blockquote&gt;
So we are anticipating a long rollout cycle for PHP 6, and we did not want to take the same route that the Perl project did, with project contributors still working on Perl 6 I think six years later. People make fun of Microsoft, but take a look at Perl 6. . . .&lt;/blockquote&gt;
&lt;br /&gt;
To which Andy Lester of PerlBuzz &lt;a href="https://web.archive.org/web/20140802224335/http://perlbuzz.com/2008/02/tell-us-how-to-do-it-andi.html"&gt;replied&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;
Sure, PHP 6 may have a shorter release cycle than Perl 6 has, but at the end of it all, we'll have Perl 6, and you'll still have PHP.
&lt;br /&gt;
&lt;br /&gt;
Just sayin'.
&lt;br /&gt;
xoxo,&lt;br /&gt;
Andy&lt;/blockquote&gt;
So how did those predictions work out? Well, after a little over six years of development, we discovered that we were &lt;a href="https://philsturgeon.uk/php/2014/07/23/neverending-muppet-debate-of-php-6-v-php-7/"&gt;never going to see a PHP 6 at all&lt;/a&gt;. Having seen how long Perl 6 had taken, and how long PHP 6 was taking, the number 6 is associated with failure. So they cancelled PHP 6 and voted to change the name to PHP 7. Problem solved! No, really, this is some of the actual reasoning given by people on the 6 to 7 RFC. (Someone should tell the ES6 folks before the curse strikes our browsers!)&lt;br /&gt;
&lt;br /&gt;
But the main intent of the renumbering was to justify a much reduced scope of new features for the next major version of PHP. &lt;a href="http://www.phpclasses.org/blog/post/242-PHP-7-Features-and-Release-Date.html"&gt;PHP 7 is slated to add&lt;/a&gt;:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;"Huge Performance Improvements" to the Zend engine (HHVM already pretty speedy)&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;JIT to the Zend engine (but already available in HHVM)&lt;/strike&gt;&lt;/li&gt;
&lt;li&gt;Abstract Syntax Tree (AST) generation&lt;/li&gt;
&lt;li&gt;Asynchronous IO and functions&lt;/li&gt;
&lt;li&gt;Standalone Multi-threading Web Server (HHVM)
&lt;ul&gt;
&lt;li&gt;Which is cool if you want a language to provide its own server, I guess &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;EDIT&lt;/b&gt;: People both here and on &lt;a href="https://news.ycombinator.com/item?id=9484939"&gt;Hacker News&lt;/a&gt; have pointed out that this is the above feature list was from a bad source, and that much of PHP 6 was incorporated into 5.3.&amp;nbsp; See the &lt;a href="https://blog.engineyard.com/2015/what-to-expect-php-7"&gt;better summary of PHP 7 features&lt;/a&gt;, including generator improvements, and new operators like &lt;span style="background-color: #eeeeee;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;??&lt;/span&gt;&lt;/span&gt;.&amp;nbsp; However, much of the same analysis still applies -- the end result was very few backwards incompatible changes, not the major revision promised with major Unicode improvements.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 id="perl-6"&gt;
Perl 6&lt;/h2&gt;
Meanwhile Perl 6, which has taken 15 years to get to the 6.0.0 release slated for &lt;i&gt;this&lt;/i&gt; Christmas.&amp;nbsp; I'm sure that there were some embarrassing quotes about when it's going to be done, but that was so long ago, I'll just link to &lt;a href="http://blogs.perl.org/users/steven_haryanto/2013/03/dont-wait-for-perl-6-to-build-your-product-on.html"&gt;this post forecasting&lt;/a&gt; that Perl 6 will be ready for production in 2027.&lt;br /&gt;
&lt;br /&gt;
As it now stands, Perl 6 comes with this &lt;a href="http://perl6.org/compilers/features"&gt;set of new features&lt;/a&gt;:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;A real type system (not just type hints as in PHP) everywhere
&lt;ul&gt;
&lt;li&gt;The ability to continue ignoring types most short scripting code&lt;/li&gt;
&lt;li&gt;The ability to use static type checks to catch errors&lt;/li&gt;
&lt;li&gt;Native types (C strings, unsigned ints, etc.) unlock new performance potential&lt;/li&gt;
&lt;li&gt;Meta-object programming is available&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A sane native function calling interface&lt;/li&gt;
&lt;li&gt;Rakudo Perl 6 runs on multiple virtual machines (JVM, MoarVM), with more backends planned (Javascript)
&lt;ul&gt;
&lt;li&gt;Can compile P6 to bytecode or an AST&lt;/li&gt;
&lt;li&gt;Takes advantage of VM's JIT&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Complete syntax refactoring
&lt;ul&gt;
&lt;li&gt;Fully backwards compatible with the use of Inline::Perl5&lt;/li&gt;
&lt;li&gt;Consistent syntax throughout&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Native Unicode handling, with NFG (grapheme) strings by default&lt;/li&gt;
&lt;li&gt;Hygienic macros
&lt;ul&gt;
&lt;li&gt;As I said above, AST&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Regexes have evolved to Grammars, a first class language
&lt;ul&gt;
&lt;li&gt;PCRE are no longer Perl-compatible (except in Perl 5 mode), but are instead much easier to read&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Easy to use concurrency
&lt;ul&gt;
&lt;li&gt;Some operators will autothread&lt;/li&gt;
&lt;li&gt;Junction types for set operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Module versioning to ensure that even if a module completely changes its API, your code will not break. If you declare a version, of course.&lt;/li&gt;
&lt;/ul&gt;
Honestly, there are a whole lot more of these features. This even excludes things that have already made back into the Perl 5 core, like subroutine signatures and smartmatching. And these are all things that are working &lt;i&gt;today&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
The eerie thing is that Andy's flippant prediction came true. At the end of it, we have Perl 6, and they still have the same old PHP. Let me repeat that: &lt;i&gt;we have Perl 6&lt;/i&gt;. It works, it will get a major release this year, and it is going to come with many more features than originally promised.&lt;br /&gt;
&lt;br /&gt;
Still, Perl 6 has had its share of doubters. Some people proposed, actually seriously, that &lt;a href="http://blogs.perl.org/users/ovid/2013/02/perl-7.html"&gt;Perl 5 should leapfrog ahead to Perl 7&lt;/a&gt; with the next version, and Perl 6 can go on calling itself that if it wants. Right. While this idea was rejected by the general Perl community, PHP actually skipped a version a year later. I guess it's another example of PHP stealing the worst ideas from Perl.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 id="python-3"&gt;
Python 3&lt;/h2&gt;
The Python group, on the other hand, has tried to stay mostly on the side of sanity. Python 3 introduced a much smaller set of breaking changes, in order to keep updates rolling out. It was introduced, well, six years ago in early 2009.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://docs.python.org/release/3.1.2/whatsnew/3.0.html"&gt;New features of Python 3&lt;/a&gt; included:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Sane Unicode handling
&lt;ul&gt;
&lt;li&gt;A breaking change that allowed all of the other breaking changes to happen&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Various name changes for style consistency&lt;/li&gt;
&lt;li&gt;Automatically loading C modules when available.&lt;/li&gt;
&lt;li&gt;Refactor of exceptions&lt;/li&gt;
&lt;li&gt;Support for ancient OSes dropped&lt;/li&gt;
&lt;li&gt;Old functions removed, along with generally bad APIs&lt;/li&gt;
&lt;li&gt;Statement form &lt;code&gt;print&lt;/code&gt; removed in favor of function &lt;code&gt;print()&lt;/code&gt;, ostensibly to make a consistent API &lt;span style="font-size: xx-small;"&gt;but really just to mess with people&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
So how's that working out? The latest version of python preinstalled on my fully updated MacBook is 2.7.6. At least Ubuntu gives me 3.4.0 — Apple is well known to be crap at updating OSS. But you'd think someone at Apple would have cared in six years would have cared enough to throw python3 in the XCode monster download; after all, Python does not have the &lt;a href="https://news.ycombinator.com/item?id=3559990"&gt;kiss of death&lt;/a&gt; known as the GPLv3 license.&lt;br /&gt;
&lt;br /&gt;
The flip side of availability is developer adoption; this story isn't much better. If you look at &lt;a href="https://blog.newrelic.com/2014/01/21/python-3-adoption-web-apps/"&gt;statistics from a last year&lt;/a&gt; and &lt;a href="http://lwn.net/Articles/640181/"&gt;this month&lt;/a&gt;, Python 3 adoption rates are abysmal. Hell, even 23% of people inside the Python community &lt;a href="https://wiki.python.org/moin/2.x-vs-3.x-survey"&gt;still think Python 3 was a mistake&lt;/a&gt;. Despite obvious improvements, it's still considered a tough sell.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 id="second-deployment-syndrome"&gt;
Second Deployment Syndrome&lt;/h2&gt;
So the takeaway from all of this is that &lt;a href="http://en.wikipedia.org/wiki/The_Mythical_Man-Month#The_second-system_effect"&gt;Second System Syndrome&lt;/a&gt; is a real problem, but not the only problem. Successfully executing major revisions to a language is difficult, but getting widespread &lt;i&gt;adoption&lt;/i&gt; is just as difficult with breaking changes. &lt;i&gt;Second Deployment Syndrome&lt;/i&gt; can be just as hard to face as making the new system in the first place.&lt;br /&gt;
&lt;br /&gt;
So we have three software communities that took radically different approaches to building a second system. PHP is a &lt;a href="http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/"&gt;complete zoo of awful design&lt;/a&gt;, begging to be tamed. Yet the PHP community effectively voted to give up, and only offer incremental change that doesn't address PHP 6's number one issue of Unicode support. The Python folks, bless their hearts, made a smaller set of achievable changes, implemented it in 3 years, and shipped the damn thing. And despite the truly useful improvements, only a few people came.&lt;br /&gt;
&lt;br /&gt;
Perl decided to stick to its vision of "break all the things once", and it's taken 15 long years. That's almost as long as the HTML 5 spec. Over this time, the design has continued to evolve, incorporating more modern needs like easily multithreaded code that would have otherwise been missed. Although the complaint of "no final spec" is common, it has been learned the hard way that the spec is the very last thing that should be finalized.&lt;br /&gt;
&lt;br /&gt;
It's easy to naively say that 15 years is a ridiculous amount of development time, but it's obvious from looking at second systems for the other scripting languages, Perl 6 was never going to complete such a major transition in less than a decade. What's still unclear is whether this transition is going to work out for Perl.&lt;br /&gt;
&lt;br /&gt;
Nearly everyone who tries Perl 6 from a Perl 5 background likes it immensely, which is usually followed up by a "can this not be so &lt;i&gt;slow&lt;/i&gt;?" Optimization is still getting there, just not prematurely. In general, reception has been a net positive. And unlike the breaking changes introduced in the other languages, Inline::Perl5 allows multiple versions of Perl to coexist in the same program.&lt;br /&gt;
&lt;br /&gt;
Will this be enough? It's too early to tell. Perl 5 is going to last another 5 years at the minimum, if not forever, munging text output by a shell script written by a programmer from generations ago. Perl 6 will have an uphill battle with Perl 5 for ubiquity, legacy code, and language familiarity.&lt;br /&gt;
&lt;br /&gt;
Adoption rate is the next big challenge facing Perl 6. There is a very real possibility that six years from now, Perl 5 will still be the dominant form of an ever shrinking faction of Perl users. After all, Python might be in the &lt;a href="http://en.wikipedia.org/wiki/TIOBE_index"&gt;same boat&lt;/a&gt; right now. Perl needs to reverse an already existing downward trend, at least partially brought on by how frakking long Perl 6 took in the first place.&lt;br /&gt;
&lt;br /&gt;
The best advice I can see for ensuring Perl 6's success is for Perl developers to &lt;b&gt;start writing code in Perl 6&lt;/b&gt;. I mean now; it's definitely stable enough. Every module available within a year of release is going to be a major argument for people to try the new version. Getting Shit Done can win a lot of arguments.&lt;br /&gt;
&lt;br /&gt;
After that, it's going to be a tough slog. Is it deployed enough places to distribute code in? Is there enough code written in it to deploy to more places? Package managers like apt and Homebrew are going to help with bootstrapping the user base, but to win Perl 6 going to have to get that killer app.&lt;br /&gt;
&lt;br /&gt;
So for now, it's a giant gamble. In poker terms, Python 3 called, PHP 6 folded, and Perl 6 went all-in. It just might be possible that Perl 6's crazy long development process can produce the best-adopted second system around, if people decide that the overwhelming improvements are worth the hassle of upgrading.&lt;br /&gt;
&lt;br /&gt;
I'll let you know how that went in six years.</content>
    <link rel="replies" type="application/atom+xml" href="http://blog.brentlaabs.com/feeds/5454750255157559759/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://blog.brentlaabs.com/2015/05/three-tales-of-second-system-syndrome.html#comment-form" title="13 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/5454750255157559759"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/5454750255157559759"/>
    <link rel="alternate" type="text/html" href="http://blog.brentlaabs.com/2015/05/three-tales-of-second-system-syndrome.html" title="Three Tales of Second System Syndrome"/>
    <author>
      <name>Brent Laabs</name>
      <uri>http://www.blogger.com/profile/17518100165641296059</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>13</thr:total>
  </entry>
  <entry>
    <title>Parrot 7.4.0 "Festive Amazon" released! by Bruce Gray</title>
    <link rel="alternate" href="https://www.nntp.perl.org/group/perl.perl6.announce/2015/05/msg726.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">On behalf of the Parrot team, I'm proud to announce Parrot 7.4.0, also known
<br/>as "Festive Amazon".  Parrot (http://parrot.org/) is a virtual machine aimed
<br/>at running all dynamic languages.
<br/>
<br/>Parrot 7.4.0 is available on Parrot's FTP site
<br/>(ftp://ftp.parrot.org/pub/parrot/releases/devel/7.4.0/), or by following the
<br/>download instructions at http://parrot.org/download.  For those who would like
<br/>to develop on Parrot, or help develop Parrot itself, we recommend using Git to
<br/>retrieve the source code to get the latest and best Parrot code.
<br/>
<br/>Parrot 7.4.0 News:
<br/>    - Documentation
<br/>        + Many minor corrections
<br/>    - Community
<br/>        + Coverity scans to resume RSN.
<br/>
<br/>
<br/>The SHA256 message digests for the downloadable tarballs are:
<br/>b191da72e668c5bd97e1792a1b5d8fe66713819066f6a2f5eef2e9bc21d92968 parrot-7.4.0.tar.gz
<br/>724868f94bf7d45ba5cda29b041b18fc7cbcd2fe5196455cc3882c2f99a84f4b parrot-7.4.0.tar.bz2
<br/>
<br/>Many thanks to all our contributors for making this possible, and our sponsors
<br/>for supporting this project.  Our next scheduled release is at 16 Jun 2015.
<br/>
<br/>Enjoy!
<br/>
<br/></div>
    </content>
    <id>https://www.nntp.perl.org/group/perl.perl6.announce/2015/05/msg726.html</id>
    <published>2015-05-20T14:59:53Z</published>
    <updated>2015-05-20T14:59:53Z</updated>
  </entry>
  <entry>
    <title>Parrot 7.3.0 release announcement by Reini Urban</title>
    <link rel="alternate" href="https://www.nntp.perl.org/group/perl.perl6.announce/2015/04/msg725.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">On behalf of the Parrot team, I'm proud to announce Parrot 7.3.0, also<br/>known as "Peach-faced Lovebird".<br/>It is a supported release with a stable API until 7.6.0 end of July 2015.<br/>Parrot (http://parrot.org/) is a virtual machine aimed at running all<br/>dynamic languages.<br/><br/>Parrot 7.3.0 is available on Parrot's FTP site<br/>(ftp://ftp.parrot.org/pub/parrot/releases/supported/7.3.0/), or by following the<br/>download instructions at http://parrot.org/download.  For those who<br/>would like to develop on Parrot, or help develop Parrot itself, we<br/>recommend using Git to retrieve the source code to get the latest and<br/>best Parrot code.<br/><br/>Parrot 7.3.0 News:<br/>    - Build<br/>        + Fixed windows link regression from 7.0.2 with cl.exe. #1203<br/>        + Fixed rlimit compilation for OpenBSD<br/>    - Tests<br/>        + Relaxed the common GC stress test and re-add the JSON.nqp variant.<br/><br/><br/>The SHA256 message digests for the downloadable tarballs are:<br/>23d2f59a0399a63a835087a192bede02a25f21fbcf5e42ed113b4c6dcdbea6b1<br/>parrot-7.3.0.tar.gz<br/>a40a6a21965ead120ceee7ac98e3b0ba2edbdfa2a5d8637ace91dcc7991373f2<br/>parrot-7.3.0.tar.bz2<br/><br/>Many thanks to all our contributors for making this possible, and our<br/>sponsors for supporting this project.  Our next scheduled release is<br/>at 19 May 2015.<br/><br/>Enjoy!<br/></div>
    </content>
    <id>https://www.nntp.perl.org/group/perl.perl6.announce/2015/04/msg725.html</id>
    <published>2015-04-21T17:58:08Z</published>
    <updated>2015-04-21T17:58:08Z</updated>
  </entry>
  <entry>
    <title>Parrot 7.2.0 "Blue-crowned racquet-tail" released! by Bruce Gray</title>
    <link rel="alternate" href="https://www.nntp.perl.org/group/perl.perl6.announce/2015/03/msg724.html" type="text/html"/>
    <content type="text">   This is the bright candlelit room where the life-timers are
&lt;br/&gt;   stored&amp;mdash;shelf upon shelf of them, squat hourglasses, one for every
&lt;br/&gt;   living person, pouring their fine sand from the future into the past.
&lt;br/&gt;   The accumulated hiss of the falling grains makes the room roar like
&lt;br/&gt;   the sea.
&lt;br/&gt;
&lt;br/&gt;   This is the owner of the room, stalking through it with a preoccupied air.
&lt;br/&gt;   His name is Death.
&lt;br/&gt;
&lt;br/&gt;   But not any Death. This is the Death whose particular sphere of
&lt;br/&gt;   operations is, well, not a sphere at all, but the Discworld, which is
&lt;br/&gt;   flat and rides on the back of four giant elephants who stand on the
&lt;br/&gt;   shell of the enormous star turtle Great A&amp;rsquo;Tuin, and which is bounded by
&lt;br/&gt;   a waterfall that cascades endlessly into space.
&lt;br/&gt;
&lt;br/&gt;   Scientists have calculated that the chance of anything so patently
&lt;br/&gt;   absurd actually existing are millions to one.
&lt;br/&gt;
&lt;br/&gt;   But magicians have calculated that million-to-one chances crop up nine
&lt;br/&gt;   times out of ten.
&lt;br/&gt;
&lt;br/&gt;           -- &amp;quot;Mort&amp;quot;, GNU Terry Pratchett
&lt;br/&gt;
&lt;br/&gt;On behalf of the Parrot team, I&amp;#39;m proud to announce Parrot 7.2.0, also known
&lt;br/&gt;as &amp;quot;Blue-crowned racquet-tail&amp;quot;.  Parrot (http://parrot.org/) is a virtual machine aimed
&lt;br/&gt;at running all dynamic languages. The blue-crowned racket-tail (Prioniturus discurus)
&lt;br/&gt;is a parrot found on all the larger islands of the Philippines not starting with &amp;quot;P&amp;quot;.
&lt;br/&gt;
&lt;br/&gt;Parrot 7.2.0 is available on Parrot&amp;#39;s FTP site
&lt;br/&gt;(ftp://ftp.parrot.org/pub/parrot/releases/devel/7.2.0/), or by following the
&lt;br/&gt;download instructions at http://parrot.org/download.  For those who would like
&lt;br/&gt;to develop on Parrot, or help develop Parrot itself, we recommend using Git to
&lt;br/&gt;retrieve the source code to get the latest and best Parrot code.
&lt;br/&gt;
&lt;br/&gt;Parrot 7.2.0 News:
&lt;br/&gt;   - Build
&lt;br/&gt;       + Fix warning on Win32 (with cl.exe)  when `link` is not explicitly set.
&lt;br/&gt;
&lt;br/&gt;
&lt;br/&gt;The SHA256 message digests for the downloadable tarballs are:
&lt;br/&gt;f4792fc1a82040dd855f73890de6fa26759aa62f4b4ad1aa468597592b7bf3bf parrot-7.2.0.tar.gz
&lt;br/&gt;74e5821155eaf29d7c1655fd3b5b90a84afe23361318242947c50f59da5918e1 parrot-7.2.0.tar.bz2
&lt;br/&gt;
&lt;br/&gt;Many thanks to all our contributors for making this possible, and our sponsors
&lt;br/&gt;for supporting this project.  Our next scheduled release is at 21 Apr 2015.
&lt;br/&gt;
&lt;br/&gt;Enjoy!
&lt;br/&gt;
&lt;br/&gt;</content>
    <id>https://www.nntp.perl.org/group/perl.perl6.announce/2015/03/msg724.html</id>
    <published>2015-03-19T06:06:01Z</published>
    <updated>2015-03-19T06:06:01Z</updated>
  </entry>
  <entry>
    <title>Suspending Rakudo support for Parrot</title>
    <link rel="alternate" href="http://pmthium.com/2015/02/suspending-rakudo-parrot/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>At <a href="https://fosdem.org/2015/">FOSDEM 2015</a>, Larry <a href="https://fosdem.org/2015/schedule/event/get_ready_to_party/">announced</a> that there will likely be a <a href="http://perl6.org/">Perl 6</a> release candidate in 2015, possibly around the September timeframe. What we’re aiming for is concurrent publication of a language specification that has been implemented and tested in at least one usable compilation environment — i.e., <a href="http://rakudo.org/">Rakudo Perl 6</a>.</p>
<p>So, for the rest of 2015, we can expect the Rakudo development team to be highly focused on doing only those things needed to prepare for the Perl 6 release later in the year. And, from previous planning and discussion, we know that there are three major areas that need work prior to release: the <a title="APW2014 and the Rakudo Great List Refactor" href="http://pmthium.com/2014/10/apw2014/">Great List Refactor</a> (GLR), Native Shaped Arrays (NSA), and Normalization Form Grapheme (NFG).</p>
<p>…which brings us to <a href="http://parrot.org/">Parrot</a>. Each of the above items is made significantly more complicated by Rakudo’s ongoing support for Parrot, either because Parrot lacks key features needed for implementation (NSA, NFG) or because a lot of special-case code is being used to maintain adequate performance (lists and GLR).</p>
<p>At present most of the current userbase has switched over to <a href="http://moarvm.com/">MoarVM</a> as the backend, for a multitude of reasons. And more importantly, there currently aren’t any Rakudo or NQP developers on hand that are eager to tackle these problems for Parrot.</p>
<p>In order to better focus our limited resources on the tasks needed for a Perl 6 language release later in the year, we’re expecting to suspend Rakudo’s support for the Parrot backend sometime shortly after the 2015.02 release.</p>
<p>Unfortunately the changes that need to be made, especially for the GLR, make it impractical to simply leave existing Parrot support in place and have it continue to work at a “degraded” level. Many of the underlying assumptions will be changing. It will instead be more effective to (re)build the new systems without Parrot support and then re-establish Parrot as if it is a new backend VM for Rakudo, following the techniques that were used to create JVM, MoarVM, and other backends for Rakudo.</p>
<p>NQP will continue to support Parrot as before; none of the Rakudo refactorings require any changes to NQP.</p>
<p>If there are people that want to work on refactoring Rakudo’s support for Parrot so that it’s more consistent with the other VMs, we can certainly point them in the right direction. For the GLR this will mainly consists of migrating parrot-specific code from Rakudo into NQP’s APIs. For the NSA and NFG work, it will involve developing a lot of new code and feature capabilities that Parrot doesn’t possess.</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">At FOSDEM 2015, Larry announced that there will likely be a Perl 6 release candidate in 2015, possibly around the September timeframe. What we’re aiming for is concurrent publication of a language specification that has been implemented and tested in … <a href="http://pmthium.com/2015/02/suspending-rakudo-parrot/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>pmichaud</name>
    </author>
    <id>http://pmthium.com/?p=460</id>
    <published>2015-02-16T15:47:37Z</published>
    <updated>2015-02-16T15:47:37Z</updated>
    <category term="Uncategorized"/>
  </entry>
  <entry>
    <title>Announce: Rakudo Star Release 2015.01 by Moritz Lenz</title>
    <link rel="alternate" href="https://www.nntp.perl.org/group/perl.perl6.announce/2015/02/msg723.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"># Announce: Rakudo Star Release 2015.01<br/><br/>## A useful, usable, "early adopter" distribution of Perl 6<br/><br/>On behalf of the Rakudo and Perl 6 development teams, I'm happy to<br/>announce the January 2015 release of "Rakudo Star", a useful and usable<br/>distribution of Perl 6. The tarball for the January 2015 release is<br/>available from &lt;http://rakudo.org/downloads/star/&gt;.<br/><br/>This Rakudo Star release comes with support for the MoarVM<br/>backend (all module tests pass on supported platforms) along with<br/>experimental support for the JVM backend (some module tests fail).<br/>Three shipped modules are known to fail on Parrot (zavolaj (NativeCall),<br/>jsonrpc and doc)<br/><br/>In the Perl 6 world, we make a distinction between the language<br/>("Perl 6") and specific implementations of the language such as<br/>"Rakudo Perl". This Star release includes [release 2015.01.1] of the<br/>[Rakudo Perl 6 compiler], version 7.0.1 of the [Parrot Virtual<br/>Machine], version 2015.01 of [MoarVM], plus various modules,<br/>documentation, and other resources collected from the Perl 6<br/>community.<br/><br/>[release 2015.01.1]:<br/>    https://github.com/rakudo/rakudo/blob/nom/docs/announce/2015.01.md<br/>[Rakudo Perl 6 compiler]: http://github.com/rakudo/rakudo<br/>[Parrot Virtual Machine]: http://parrot.org<br/>[MoarVM]: http://moarvm.org/<br/><br/>Some of the new compiler features added to this release include:<br/><br/>+ Many improvements to Java interop for the JVM backend<br/>+ New simple way of creating an object hash: :{}<br/>+ Substitution now supports assignment meta-op, e.g. s[\d+] += 2<br/>+ Many memory and CPU optimizations<br/>+ Supply.for deprecated in favour of Supply.from-list<br/><br/>Changes to modules included in Rakudo Star:<br/><br/>- [Bailador](https://github.com/tadzik/Bailador) handles POST and URL<br/>params separately<br/>- [DBIish](https://github.com/perl6/DBIish) has improved error reporting<br/>on SQLite<br/>- [doc](https://github.com/perl6/doc) ships with much more documentation<br/>- [panda](https://github.com/tadzik/panda) has a new command `installdeps`<br/>- [Pod::To::HTML](https://github.com/perl6/Pod-To-HTML) now supports<br/>callbacks for code areas<br/><br/>Parrot support will likely be suspended or dropped from future Rakudo<br/>and Rakudo<br/>Star releases, starting with the February or March releases.<br/><br/>In the next Rakudo Star release, modules `Math::RungeKutta` and<br/>`Math::Model`<br/>will likely be dropped. They can still be installed with `panda`.<br/><br/>In future, the `nqp::` namespace willl only be available after a declaration<br/>like `use nqp;'.<br/><br/>There are some key features of Perl 6 that Rakudo Star does not yet<br/>handle appropriately, although they will appear in upcoming releases.<br/>Some of the not-quite-there features include:<br/><br/>  * advanced macros<br/>  * threads and concurrency (in progress for the JVM and MoarVM backend)<br/>  * Unicode strings at levels other than codepoints<br/>  * interactive readline that understands Unicode<br/>  * non-blocking I/O (in progress for the JVM and MoarVM backend)<br/>  * much of Synopsis 9 and 11<br/><br/>There is an online resource at &lt;http://perl6.org/compilers/features&gt;<br/>that lists the known implemented and missing features of Rakudo's<br/>backends and other Perl 6 implementations.<br/><br/>In many places we've tried to make Rakudo smart enough to inform the<br/>programmer that a given feature isn't implemented, but there are many<br/>that we've missed. Bug reports about missing and broken features are<br/>welcomed at &lt;rakudobug@perl.org&gt;.<br/><br/>See &lt;http://perl6.org/&gt; for links to much more information about<br/>Perl 6, including documentation, example code, tutorials, reference<br/>materials, specification documents, and other supporting resources. A<br/>draft of a Perl 6 book is available as docs/UsingPerl6-draft.pdf in<br/>the release tarball.<br/><br/>The development team thanks all of the contributors and sponsors for<br/>making Rakudo Star possible. If you would like to contribute, see<br/>&lt;http://rakudo.org/how-to-help&gt;, ask on the &lt;perl6-compiler@perl.org&gt;<br/>mailing list, or join us on IRC \#perl6 on freenode.<br/></div>
    </content>
    <id>https://www.nntp.perl.org/group/perl.perl6.announce/2015/02/msg723.html</id>
    <published>2015-02-07T23:23:53Z</published>
    <updated>2015-02-07T23:23:53Z</updated>
  </entry>
  <entry>
    <title>Parrot 7.0.2 Hotfix released by Reini Urban</title>
    <link rel="alternate" href="https://www.nntp.perl.org/group/perl.perl6.announce/2015/01/msg722.html" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">We detected and fixed two bugs and regressions from 6.10.0 which<br/>failed to build parrot on Microsoft Windows with Microsoft Visual<br/>Studio C++.<br/><br/>- Wrong function ptr cast on win64<br/>  https://github.com/parrot/parrot/issues/1190<br/>- Wrong SAL annotations on msvc cl &lt; 16.00<br/>  https://github.com/parrot/parrot/issues/1192<br/><br/>Other minor changes in this hotfix:<br/>- Optimize away ExtUtils::Command on posix systems. #1177<br/>- Fix cpu config values for gcc_cmpxchg to include atomic/gcc_x86.o on amd64.<br/>  Harmonized the cpu config keys, no $platform_has_$feature<br/>  keys anymore, just HAS_$PLATFORM_$feature. #1173<br/>- Improved msvc configuration from a mingw perl. #1191<br/><br/>Parrot is a virtual machine aimed at running all dynamic languages.<br/>Parrot 7.0.2 is available on Parrot's FTP site, or by following the<br/>download instructions. For those who want to hack on Parrot or<br/>languages that run on top of Parrot, we recommend our organization<br/>page on GitHub, or you can go directly to the official Parrot Git repo<br/>on Github<br/><br/>To clone the Parrot Git repo into a directory called 'parrot', use the<br/>following:<br/>    git clone git://github.com/parrot/parrot.git<br/><br/>If you want it to be in a directory other than 'parrot', then just<br/>give that as a second argument to clone:<br/>    git clone git://github.com/parrot/parrot.git parrot_foo<br/><br/>The SHA256 message digests for the downloadable tarballs are:<br/>1a8e9e203ad8ac92c89422603d1603fa821e957aa3a9ae57420c737d93c55213<br/>parrot-7.0.2.tar.gz<br/>2cc8dc1eada38bb6328bf1f4648bd5e01e000b415f984b7ad6b5b6c123a15ac9<br/>parrot-7.0.2.tar.bz2<br/><br/>Thanks to all our contributors for making this possible, and our<br/>sponsors for supporting this project. Our next scheduled release is at<br/>17 Feb 2015.<br/>Enjoy!<br/>-- <br/>Reini Urban<br/>http://cpanel.net/   http://www.perl-compiler.org/<br/></div>
    </content>
    <id>https://www.nntp.perl.org/group/perl.perl6.announce/2015/01/msg722.html</id>
    <published>2015-01-29T14:02:38Z</published>
    <updated>2015-01-29T14:02:38Z</updated>
  </entry>
  <entry>
    <title>APW2014 and the Rakudo Great List Refactor</title>
    <link rel="alternate" href="http://pmthium.com/2014/10/apw2014/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>This past weekend I attended the <a href="http://act.useperl.at/apw2014/">2014 Austrian Perl Workshop and Hackathon</a> in Salzburg, which turned out to be an excellent way for me to catch up on recent changes to <a href="http://perl6.org/">Perl 6</a> and <a href="http://rakudo.org/">Rakudo</a>. I also wanted to participate directly in discussions about the Great List Refactor, which has been a longstanding topic in Rakudo development.</p>
<p>What exactly is the “Great List Refactor” (GLR)? For several years Rakudo developers and users have identified a number of problems with the existing implementation of list types — most notably performance. But we’ve also observed the need for user-facing changes in the design, especially in generating and flattening lists.  So the term GLR now encompasses all of the list-related changes that seem to want to be made.</p>
<p>It’s a significant (“great”) refactor because our past experience has shown that small changes in the list implementation often have far-reaching effects. Almost any bit of rework of list fundamentals requires a fairly significant refactor throughout much of the codebase. This is because lists are so fundamental to how Perl 6 works internally, just like the object model. So, as the number of things that are desirable to fix or change has grown, so has the estimated size of the GLR effort, and the need to try to achieve it “all at once” rather than piecemeal.</p>
<p>The pressure to make progress on the GLR has been steadily increasing, and APW2014 was significant in that a lot of the key people needed for that would be in the same location. Everyone I’ve talked to agrees that APW2014 was a smashing success, and I believe that we’ve now resolved most of the remaining GLR design issues. The rest of this post will describe that.</p>
<p>This is an appropriate moment to recognize and thank the people behind the APW effort. The organizers did a great job.  The Techno-Z and ncm.at venues were fantastic locations for our meetings and discussions, and I especially thank <a href="http://ncm.at/">ncm.at</a>, <a href="http://www.techno-z.at/">Techno-Z</a>, <a href="http://www.yelsterdigital.com/">yesterdigital</a>, and <a href="http://vienna.pm.org/">vienna.pm</a> for their generous support in providing venues and food at the event.</p>
<p>So, here’s my summary of GLR issues where we were able to reach significant progress and consensus.</p>
<h2>You are now leaving flatland</h2>
<p>(Be sure to visit our gift shop!)</p>
<p>Much of the GLR discussion at APW2014 concerned flattening list context in Perl 6. Over the past few months and years Perl 6 has slowly but steadily reduced the number of functions and operators that flatten by default. In fact, a very recent (and profound) change occurred within the last couple of months, when the <code>.[]</code> subscript operator for Parcels switched from flattening to non-flattening. To illustrate the difference, the expression</p>
<pre>(10,(11,12,13),(14,15)).[2]</pre>
<p>previously would flatten out the elements to return 12, but now no longer flattens and produces <code>(14,15)</code>. As a related consequence, <code>.elems</code> no longer flattens either, changing from 6 to 3.</p>
<p>Unfortunately, this change created a inconsistency between Parcels and Lists, because <code>.[]</code> and <code>.elems</code> on Lists continued to flatten. Since programmers often don’t know (or care) when they’re working with a Parcel or a List, the inconsistency was becoming a significant pain point. Other inconsistencies were increasing as well: some methods like <code>.sort</code>, <code>.pick</code>, and <code>.roll</code> have become non-flattening, while other methods like <code>.map</code>, <code>.grep</code>, and <code>.max</code> continue to flatten. There’s been no really good guideline to know or decide which should do which.</p>
<p>Flattening behavior is great when you want it, which is a lot of the time.  After all, that’s what Perl 5 does, and it’s a pretty popular language. But once a list is flattened it’s hard to get the original structure if you wanted that — flattening discards information.</p>
<p>So, after many animated discussions, review of lots of code snippets, and seeking some level of consistency, the consensus on Perl 6 flattening behavior seems to be:</p>
<div class="lispace">
<ul>
<li>List assignment and the <code>[ ]</code> array constructor are unchanged; they continue to flatten their input elements. (Arrays are naturally flat.)</li>
<li>The for statement is unchanged. <code>for @a,@b { ... }</code> flattens <code>@a,@b</code> and applies the block to each element of <code>@a</code> followed by each element of <code>@b</code>. Note that flattening can easily be suppressed by itemization, thus <code>for @a, $@b { ... }</code> flattens <code>@a</code> but does all of <code>@b</code> in a single iteration.</li>
<li>Method calls tend to not flatten their invocant. This most impacts <code>.map</code>, <code>.grep</code>, and <code>.first</code>… the programmer will have to use <code>.flat.grep</code> and <code>.flat.first</code> to flatten the list invocant.  Notably, <code>.map</code> will no longer flatten its invocant — a significant change — but we’re introducing <code>.for</code> as a shortcut for <code>.flat.map</code> to preserve a direct isomorphism with the <code>for</code> statement.There’s ongoing conjecture of creating an operator or syntax for flattening, likely a postfix of some sort, so that something like <code>.|grep</code> would be a convenient alternative to <code>.flat.grep</code>, but it doesn’t appear that decision needs to be made as part of the GLR itself.</li>
<li>Argument lists continue to depend on the context in which they are bound: flattening for slurpy parameters, top-level itemizing for slice parameters, and non-flattening (or deferred flattening) for Positionals.</li>
<li>The above two points produce a general guideline that method call invocants are generally not-flattened, while function call arguments are more likely to be.
<pre>((1,2), 3, (4,5)).map({...}) # iterates over three elements
map {...}, ((1,2),3,(4,5))   # iterates over five elements

(@a, @b, @c).pick(1)         # picks one of three arrays
pick 1, @a, @b, @c           # flatten arrays and pick one element
</pre>
</li>
<li>We think it will be very difficult to have a guideline that applies 100% of the time — there will be a few exceptions to the rule but they should generally feel natural.</li>
<li>The flattening behavior of operators continues to be specific to each operator — some will flatten, others will not. Fortunately, any flattening behavior should be grouped by precdence level, is generally dwimmy, and there are easy ways to use contextualizers to quickly switch to the behavior you want.</li>
</ul>
<h2>United Parcel Severance</h2>
<p>As a result of improvements in flattening consistency and behavior, it appears that we can eliminate the Parcel type altogether. There was almost unanimous agreement and enthusiasm at this notion, as having both the Parcel and List types is quite confusing.</p>
<p>Parcel was originally conceived for Perl 6 as a “hidden type” that programmers would rarely encounter, but it didn’t work out that way in practice. It’s nice that we may be able to hide it again — by eliminating it altogether. <img src="https://s.w.org/images/core/emoji/2.2.1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;"/></p>
<p>Thus <code>infix:&lt;,&gt;</code> will now create Lists directly. It’s likely that comma-Lists will be immutable, at least in the initial implementation. Later we may relax that restriction, although immutability also provides some optimization benefits, and Jonathan points out that may help to implement fixed-size Arrays.</p>
<p>Speaking of optimization, eliminating Parcel may be a big boost to performance, since Rakudo currently does a fair bit of converting Parcels to Lists and vice-versa, much of which goes away if everything is a List.</p>
<h2>A few more times around the (loop) blocks</h2>
<p>During a dinner discussion Jonathan reminded me that Synopsis 4 has all of the looping constructs as list generators, but Rakudo really only implements <code>for</code> at the moment. He also pointed out that if the loop generators are implemented, many functions that currently use <code>gather/take</code> could potentially use a loop instead, and this could be much more performant. After thinking on it a bit, I think Jonathan is on to something. For example, the code for <code>IO::Handle.lines()</code> currently does something like:</p>
<pre>gather {
    until not $!PIO.eof {
        $!ins = $!ins + 1;
        take self.get;
    }
 }</pre>
<p>With a lazy <code>while</code> generator, it could be written as</p>
<pre>(while not $!PIO.eof { $!ins++; self.get });</pre>
<p>This is lazily processed, but doesn’t involve any of the exception or continuation handling that <code>gather/take</code> requires. And since <code>while</code> might choose to not be strictly lazy, but <code>lines()</code> definitely should be, we may also use the <code>lazy</code> statement prefix:</p>
<pre>lazy while not $!PIO.eof { $!ins++; self.get };</pre>
<p>The <code>lazy</code> prefix tells the list returned from the <code>while</code> that it’s to generate as lazily as it possibly can, only returning the minimum number of elements needed to satisfy each request.</p>
<p>So as part of the GLR, we’ll implement the lazy list forms of all of the looping constructs (<code>for</code>, <code>while</code>, <code>until</code>, <code>repeat</code>, <code>loop</code>). In the process I also plan to unify them under a single <code>LoopIter</code> type, which can avoid repetition and be heavily optimized.</p>
<p>This new loop iterator pattern should also make it possible to improve performance of <code>for</code> statements when performed in sink context. Currently <code>for</code> statements always generate calls to <code>.map</code>, passing the body of the loop as a closure. But in sink context the block of a <code>for</code> statement could potentially be inlined. This is the way blocks in most other loops are currently generated. Inlining the block of the body could greatly increase performance of <code>for</code> loops in sink context (which are quite common).</p>
<p>Many people are aware of the problem that constructs such as <code>for</code> and <code>map</code> aren’t “consuming” their input during processing. In other words, if you’re doing <code>.map</code> on a temporary list containing a million elements, the entire list stays around until all have been processed, which could eat up a lot of memory.</p>
<p>Naive solutions to this problem just don’t work — they carry lots of nasty side effects related to binding that led us to design immutable Iterators. We reviewed a few of them at the hackathon, and came back to the immutable Iterator we have now as the correct one. Part of the problem is that the current implementation is a little “leaky”, so that references to temporary objects hang around longer than we’d like and these keep the “processed” elements alive. The new implementation will plug some of the leaks, and then some judicious management of temporaries ought to take care of the rest.</p>
<h2>I’ve got a sinking feeling…</h2>
<p>In the past year much work has been done to improve sink context to Rakudo, but I’ve never felt the implementation we have now is what we really want. For one, the current approach bloats the codegen by adding a call to <code>.sink</code> after every sink-context statement (i.e., most of them). Also, this only handles sink for the object returned by a Routine — the Routine itself has no way of knowing it’s being called in sink context such that it could optimize what it produces (and not bother to calculate or return a result).</p>
<p>We’d really like each Routine to know when it’s being called in sink context.  Perl 5 folks will instantly say “Hey, that’s <code>wantarray</code>!”, which we long ago determined <a href="http://faq.perl6.org/#want">isn’t generally feasible in Perl 6</a>.</p>
<p>However, although a generalized <code>wantarray</code> is still out of reach, we <em>can</em> provide it for the limited case of detecting sink contexts that we’re generating now, since those are all statically determined. This means a Routine can check if it’s been called in sink context, and use that to select a different codepath or result.  Jonathan speculates that the mechanism will be a flag in the callsite, and I further speculate the Routine will have a macro-like keyword to check that flag.</p>
<p>Even with detecting context, we still want any objects returned by a Routine to have <code>.sink</code> invoked on them.  Instead of generating code for this after each sink-level statement, we can do it as part of the general return handler for Routines; a Routine in sink context invokes <code>.sink</code> on the object it would’ve otherwise returned to the caller.  This directly leads to other potential optimizations:  we can avoid <code>.sink</code> on some objects altogether by checking their type, and the return handler probably doesn’t need to do any decontainerizing on the return value.</p>
<p>As happy as I am to have discovered this way to pass sink context down into Routines, please don’t take this as opening an easy path to lots of other wantarray-like capabilities in Perl 6. There may be others, and we can look for them, but I believe sink context’s static nature (as well as the fact that a false negative generally isn’t harmful) makes it quite a special case.</p>
<h2>The value of consistency</h2>
<p>One area that has always been ambiguous in the Synopses is determining when various contextualizing methods must return a copy or are allowed to return <code>self</code>. For example, if I invoke <code>.values</code> on a List object, can I just return <code>self</code>, or must I return a clone that can be modified without affecting the original? What about <code>.list</code> and <code>.flat</code> on an already-flattened list?</p>
<p>The ultra-safe answer here is probably to always return a copy… but that can leave us with a lot of (intermediate) copies being made and lying around. Always returning <code>self</code> leads to unwanted action-at-a-distance bugs.</p>
<p>After discussion with Larry and Jonathan, I’ve decided that true contextualizers like <code>.list</code> and <code>.flat</code> are allowed to return <code>self</code>, but other method are generally obligated to return an independent object.  This seems to work well for all of the methods I’ve considered thus far, and may be a general pattern that extends to contextualizers outside of the GLR.</p>
<h2>Now it’s just a SMOPAD</h2>
<p>(small matter of programming and documentation)</p>
<p>The synopses — especially Synopsis 7 — have always been problematic in describing how lists work in Perl 6. The details given for lists have often been conjectural ideas that quickly prove to epic fail in practice. The last major list implementation was done in Summer 2010, and Synopsis 7 was supposed to be updated to reflect this design. However, the ongoing inconsistencies (that have led to the GLR) really precluded any meaningful update to the synopses.</p>
<p>With the progress recently made at APW2014, I’m really comfortable about where the Great List Refactor is leading us. It won’t be a trivial effort; there will be significant rewrite and refactor of the current Rakudo codebase, most of which will have to be done in a branch. And of course we’ll have to do a lot of testing, not only of the Perl 6 test suite but also the impact on the module ecosystem. But now that much of the hard decisions have been made, we have a roadmap that I hope will enable most of the GLR to be complete and documented in the synopses by Thanksgiving 2014.</p>
<p>Stay tuned.</p>
</div>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">This past weekend I attended the 2014 Austrian Perl Workshop and Hackathon in Salzburg, which turned out to be an excellent way for me to catch up on recent changes to Perl 6 and Rakudo. I also wanted to participate directly … <a href="http://pmthium.com/2014/10/apw2014/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>pmichaud</name>
    </author>
    <id>http://pmthium.com/?p=413</id>
    <published>2014-10-15T15:01:55Z</published>
    <updated>2014-10-15T15:01:55Z</updated>
    <category term="perl6"/>
    <category term="rakudo"/>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-1163079349106481731.post-7087046172458304595</id>
    <published>2013-06-22T01:23:00.000-07:00</published>
    <updated>2013-06-22T14:10:41.815-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="camelia"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <title type="text">Camelia at Age 13: Perl 6 on the JVM Debuts</title>
    <content type="html">Perl 6 is now thirteen years old.&amp;nbsp; And she's very much a teenager in attitude, self-confident yet still growing up.&amp;nbsp; This contrasts with Javascript, which emerged from Brendan Eich's head, fully-formed like Athena -- but that only shared the Zeus-sized headaches with everyone until JQuery came along.&lt;br /&gt;
&lt;br /&gt;
But Camelia, as she is fondly referred to by fans of Perl 6, is growing up fast.&amp;nbsp; Both too fast, and not fast enough.&amp;nbsp; To some of the community, the prospect of major changes to the language is scary.&amp;nbsp; Perl 6 is trying all of these crazy new things -- invariant sigils, metaoperators, grammars. She's even doing subroutine signatures, because "all of her friends are doing it".&lt;br /&gt;
&lt;br /&gt;
They can't stay little children forever, you know.&lt;br /&gt;
&lt;br /&gt;
And teenagers are liable to do surprising things.&amp;nbsp; So it was, that this week we announced Rakudo Perl 6 now &lt;a href="https://github.com/rakudo/rakudo/blob/nom/docs/announce/2013.06.md"&gt;runs on the Java Virtual Machine&lt;/a&gt; (JVM).&amp;nbsp; It's not perfect yet, but 62% of the files in the spectest pass as of yesterday.&amp;nbsp; Given the rate things are progressing, I'm sure it's already at a higher pass percent.&lt;br /&gt;
&lt;br /&gt;
And yet, I'm sure there is no small number of you whose first thought about Perl on the JVM was "Heresy!".&lt;br /&gt;
&lt;br /&gt;
There are certainly good reasons to support this point of view.&amp;nbsp; Startup times are horrible at this early stage, still O(seconds), and much of that is JVM's overhead.&amp;nbsp; It has well known security issues.&amp;nbsp; And of course the major implementation is controlled by &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;$corporation&lt;/span&gt;, who just wants to make money off it.&amp;nbsp; And why would we want to abandon open-source VMs?&lt;br /&gt;
&lt;br /&gt;
Still, there are plenty of good reasons for the port.&amp;nbsp; One is that the JVM is ubiquitous, and many devices have a copy pre-installed.&amp;nbsp; Most of Java's stability issues have been dealt with, and it serves Perl's competitors well enough through Jython and JRuby.&amp;nbsp; And it is well-documented, with bazillions of libraries (more than fooilions, anyway).&amp;nbsp; So we can finally address the longstanding desires of the community in things like sockets and threading, because we can tell the difference between our mistakes and those of the VM.&lt;br /&gt;
&lt;br /&gt;
Instead of thinking of Perl 5 as a "sister language", I like to think of it as Camelia's father instead.&amp;nbsp; A father that might be kind of upset that she brought "that kind of language" into our house.&amp;nbsp; But she has a mind of her own, and I'm afraid that this won't be the only boyfriend she'll be bringing home.&amp;nbsp; There is a &lt;a href="http://www.google-melange.com/gsoc/proposal/review/google/gsoc2013/pmurias/9002"&gt;GSoC grant&lt;/a&gt; to build a Javascript backend to Rakudo.&amp;nbsp; And &lt;a href="https://github.com/sorear/niecza"&gt;Niecza Perl 6&lt;/a&gt; already uses the .NET Runtime.&lt;br /&gt;
&lt;br /&gt;
However, Perl 6 is not abandoning open-source and C language implementations, either.&amp;nbsp; The &lt;a href="http://6guts.wordpress.com/2013/05/31/moarvm-a-virtual-machine-for-nqp-and-rakudo/"&gt;announcement of MoarVM&lt;/a&gt; shows that Perl 6 developers plan to develop a lightweight VM specifically for NQP and Rakudo.&amp;nbsp; C functions will be directly callable within Perl itself, with the &lt;a href="https://github.com/jnthn/zavolaj/"&gt;NativeCall interface&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
Now, if Parrot &lt;a href="http://lists.parrot.org/pipermail/parrot-dev/2013-June/007489.html"&gt;fly off on its own course&lt;/a&gt;, that's Parrot's call.&amp;nbsp; You know how these teenage relationships go -- this could end up in a blow-up on &lt;a href="http://www.reddit.com/r/perl"&gt;the quad&lt;/a&gt;, or just as easily turn into hot makeup coding.&amp;nbsp; What, you didn't think I was going to say something that would &lt;a href="http://blog.schwern.net/2013/05/15/yapcna-2013-withdrawal/"&gt;violate the CoC&lt;/a&gt;, did you?&lt;br /&gt;
&lt;br /&gt;
But Perl 6 is not done growing yet.&amp;nbsp; Camelia, like other teenagers, cares about fashion and wishes she had better threads.&amp;nbsp; And, once we get tuits, this is pretty high priority.&amp;nbsp; Because any modern language needs to live in the multi-core reality.&amp;nbsp; This is something that we can still design around,&amp;nbsp; that may not have recieved the same care ten years ago.&amp;nbsp; Many threading features are already baked into the language, like hyper operators and async blocks.&lt;br /&gt;
&lt;br /&gt;
So I view the debut of the JVM port as Rakudo's real début, as with a debutante.&amp;nbsp; A treceañera, if you will.&amp;nbsp; I guess, given that she's 13, maybe it's a Bar Mitzvah -- except that she's not a boy, she's a butterfly.&amp;nbsp; But this is a chance acknowledge Perl 6's presence in the language scene.&amp;nbsp; Of course, these coming-of-age ceremonies don't mean the teenager is truly grown up yet.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
But grow up she will, and faster than some of you might like.&amp;nbsp; Perl 6 is rebellious, and changes things that those in her father's Perl 5 community don't understand.&amp;nbsp; But if you talk to the pumpkings, they sincerly hope that Camelia doesn't turn out exactly like her father.&lt;br /&gt;
&lt;br /&gt;
After all, do we want keep the ithreads model?&amp;nbsp; Do we want to modules that dig into the compiler internals like XS does?&amp;nbsp; Perl 5 isn't perfect, we are just accustomed to its particular idiosyncrasies.&lt;br /&gt;
&lt;br /&gt;
But for all that Perl 6 is different, she still loves her father.&amp;nbsp; We still have sigils, classes, @_ in subs (if you still want it), P5-style regexes, modules, and TIMTOWTDI.&amp;nbsp; It's still Perl.&amp;nbsp; Moreover, there are at least two efforts to run Perl 5 code in Perl 6 -- the &lt;a href="https://github.com/rakudo-p5/v5"&gt;v5 grammar/compiler&lt;/a&gt; in Perl 6, and access to libperl from MoarVM.&amp;nbsp; So the sky isn't falling on compatibility.&lt;br /&gt;
&lt;br /&gt;
Nor is the other extreme true: Perl 6 development is in fact moving forward at a fast pace.&amp;nbsp; We know that Perl 6 is late.&amp;nbsp; Very late.&amp;nbsp; So late, in fact, that it's her father that's going to &lt;a href="http://shadow.cat/blog/matt-s-trout/pumpkin-perl-breakdown/"&gt;turn into a Pumpkin&lt;/a&gt;.&amp;nbsp; But when Perl 6 finally comes of age -- sooner than you think -- it will be something that the Perl community will be proud of.&lt;br /&gt;
&lt;br /&gt;
And I apologize in advance for anything Camelia does in her bratty teenage years.&lt;br /&gt;
&lt;br /&gt;</content>
    <link rel="replies" type="application/atom+xml" href="http://blog.brentlaabs.com/feeds/7087046172458304595/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://blog.brentlaabs.com/2013/06/camelia-at-age-13-perl-6-on-jvm-debuts.html#comment-form" title="2 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/7087046172458304595"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/7087046172458304595"/>
    <link rel="alternate" type="text/html" href="http://blog.brentlaabs.com/2013/06/camelia-at-age-13-perl-6-on-jvm-debuts.html" title="Camelia at Age 13: Perl 6 on the JVM Debuts"/>
    <author>
      <name>Brent Laabs</name>
      <uri>http://www.blogger.com/profile/17518100165641296059</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>2</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-1163079349106481731.post-5025265846367493482</id>
    <published>2013-06-06T09:37:00.002-07:00</published>
    <updated>2013-06-06T09:52:21.678-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl community"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="programming"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="yapc"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="yapcna"/>
    <title type="text">Thanking the Perl Community for an Awesome YAPC</title>
    <content type="html">My first time at &lt;a href="http://yapcna.org/"&gt;YAPC::NA&lt;/a&gt; was too incredible for words. That said, because this is a blog, I'm going to have to put it in words anyway.&lt;br /&gt;
&lt;br /&gt;
So, about a month ago, I didn't even know that I was even going to YAPC.&amp;nbsp; I was just talking to raiph++ in an IRC back channel, when he asked me if I was going to the conference.&amp;nbsp; I said that it would be fun, but I didn't really have money to go.&amp;nbsp; Being unemployed means lots of free time for hacking, but not so much free money for going places.&lt;br /&gt;
&lt;br /&gt;
Well, raiph told diakopter++, who asked if I could be willing to go, if he found funds.&amp;nbsp; I responded, "Of course, if you think it's possible."&amp;nbsp; I soon went to sleep, and twelve hours later, I had a plane ticket to Austin in my inbox courtesy of The Perl Foundation.&amp;nbsp;&amp;nbsp; So just like &lt;a href="http://blogs.perl.org/users/peter_rabbitson/2013/05/on-the-awesomeness-of-the-perl-community.html"&gt;Peter Rabbitson's case&lt;/a&gt;, the Perl community eagerly gave me a chance to attend.&amp;nbsp; So thank you to all 440 attendees, and all of the sponsors for your own personal contribution to my attendance.&amp;nbsp; Even though I'm new, you all gave a me a chance to participate in the community, and for that I am grateful.&lt;br /&gt;
&lt;br /&gt;
And what a community it is.&amp;nbsp; I've long known that Perl programmers were a little strange.&amp;nbsp; Naturally, I fit right in.&lt;br /&gt;
&lt;br /&gt;
The conference itself had quite a fun and informative series of talks.&amp;nbsp; More often than not, I had two or more that I wanted to attend at the same time.&amp;nbsp; For the most part, I stuck to the Perl 6 "track", where most of my work has been so far.&amp;nbsp; After all, it's not often that so many of the European contingent make a trip to our humble continent, so I was eager to spend time with them.&lt;br /&gt;
&lt;br /&gt;
No one warned me that jnthn++ has a tendency to spring wild new features on us at YAPCs.&amp;nbsp; &lt;a href="http://www.yapcna.org/yn2013/talk/4657"&gt;Reversible grammars&lt;/a&gt;, seriously?!&amp;nbsp; I'm still trying to wrap my head around that one.&amp;nbsp; The announcement of &lt;a href="https://github.com/moarvm/moarvm"&gt;MoarVM&lt;/a&gt; was equally exciting, as it offers us a chance to start fresh with everything we learned about Perl 6 and virtual machines in the last five years.&lt;br /&gt;
&lt;br /&gt;
So I have to say diakopter++ once again.&amp;nbsp; Besides introducing Moar in his talk, Matthew Wilson was constantly busy behind the scenes, making sure that everything ran smoothly the entire conference.&amp;nbsp; I think the man must be buying tuits on the black market.&lt;br /&gt;
&lt;br /&gt;
YAPC also helped immensely in my hunt for a job.&amp;nbsp; The job fair brought me several contacts, and the talks helped me learn which skills I'll really need to learn in those jobs.&amp;nbsp; Person-to-person contact offers so much more in truly understanding the state of the language, and of what projects are of the greatest use right now.&lt;br /&gt;
&lt;br /&gt;
Truly, Perl's community is it's greatest strength.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
It's the community that keeps Perl vital.&amp;nbsp; After seeing YAPC for myself, the whole "Perl is Dead" meme seems entirely baseless.&amp;nbsp; Conference attendance was up 19% over last year, which was the previous record high.&amp;nbsp; Perl feels like a growing language, with lots of experiments in how to revitalize the now 25-year-old syntax with p2, moe, and Perl 6.&lt;br /&gt;
&lt;br /&gt;
The community keeps Perl relevant.&amp;nbsp; While it may not be the sole alternative to bash scripts like it once was, it is used for enterprise and homebrew projects alike, from the stock exchange to the surface of Mars.&amp;nbsp; Projects like DBIx, Moose, and Dancer provide modern frameworks to acomplish more with less work.&lt;br /&gt;
&lt;br /&gt;
The community keeps Perl open.&amp;nbsp; No one seemed to be afraid to say what they felt, on CGI.pm or anything else, but everyone remained civil.&amp;nbsp; &lt;a href="http://shadow.cat/blog/matt-s-trout/hwppna-2013/"&gt;Hallway++&lt;/a&gt; is a great social hack to get everyone to feel comfortable talking to each other.&amp;nbsp; So when I found myself sitting across from TimToady, instead of being intimidated as a newbie, I had a great conversation with him about supervolcanoes and nonverbal Japanese language.&lt;br /&gt;
&lt;br /&gt;
And the community really wants &lt;i&gt;all&lt;/i&gt; of the projects to succeed.&amp;nbsp; I spent a lot of time at non-profit and political events in the past, where we were all theoretically working for a common cause.&amp;nbsp; And yet scheming, conflict, and political maneuvering were inevitable.&amp;nbsp; But in Perl, where we actually have multiple implementations and modules competing for mindshare and tuits, people cheer for everything to succeed.&amp;nbsp; No one fights each other or rages against $language_of_the_week stealing our users, for the real enemy is the lack of tuits.&lt;br /&gt;
&lt;br /&gt;
I overheard this at dinner last night, from a fellow first-time attendee:&lt;br /&gt;
&lt;blockquote&gt;
"I'm just happy that the two of you liked my work." -- vanstyn&lt;/blockquote&gt;
Although he was talking about DBIx, I think that captures the spirit of conference as a whole.&amp;nbsp; All of us here -- from the n00bs to the pumpkings -- want to share our work and make something useful for others.&amp;nbsp; It's not an organization where we wait for pronouncements from on high, but one where users create endless variations and share them.&amp;nbsp; Not an organization so much as a family.&lt;br /&gt;
&lt;br /&gt;
During TimToady's epistle/speech to the community, he said something like:&lt;br /&gt;
&lt;blockquote class="tr_bq"&gt;
"We have faith, hope, and love, but the most &lt;i&gt;awesome&lt;/i&gt; of these is love." -- Larry Wall&lt;/blockquote&gt;
A line like this might seem a bit hokey out of context, but it was actually moving when I heard it.&amp;nbsp; We have faith that we can use Perl to solve our problems.&amp;nbsp; We have hope that Perl 5 and 6 will continue to get better. And we love Perl, unconditionally, despite all of her flaws.&amp;nbsp; And as Wil Wheaton says &lt;a href="http://www.youtube.com/watch?feature=player_embedded&amp;amp;v=H_BtmV4JRSc"&gt;about us geeks&lt;/a&gt;, we just want to love our special thing the best we can, and go the extra mile to share it with others.&lt;br /&gt;
&lt;br /&gt;
I just want to say that I love the Perl community right back.&amp;nbsp; You went out of your way to include me and all the other newcomers.&amp;nbsp; You all gave me all a chance to learn, play, and code with you -- and to be part of your community -- and I am so glad you did.</content>
    <link rel="replies" type="application/atom+xml" href="http://blog.brentlaabs.com/feeds/5025265846367493482/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://blog.brentlaabs.com/2013/06/thanking-perl-community-for-awesome-yapc.html#comment-form" title="1 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/5025265846367493482"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/5025265846367493482"/>
    <link rel="alternate" type="text/html" href="http://blog.brentlaabs.com/2013/06/thanking-perl-community-for-awesome-yapc.html" title="Thanking the Perl Community for an Awesome YAPC"/>
    <author>
      <name>Brent Laabs</name>
      <uri>http://www.blogger.com/profile/17518100165641296059</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>1</thr:total>
  </entry>
  <entry>
    <title>A Perl 6 developer’s reply to a Russian Perl Podcast</title>
    <link rel="alternate" href="http://pmthium.com/2013/06/a-perl-6-developers-reply-to-a-russian-perl-podcast/" type="text/html"/>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>[This is a response to the <a href="http://yapp.rpod.ru/301370.html">Russian Perl Podcast</a> <a href="https://gist.github.com/ribasushi/5670006">transcribed</a> by Peter Rabbitson and discussed at <a href="http://blogs.perl.org/users/peter_rabbitson/2013/05/perlx-sub-communities-etc.html">blogs.perl.org</a>.]</p>
<p>I found this translation and podcast to be interesting and useful, thanks to all who put it together.</p>
<p>Since there seems to have been some disappointment that Perl 6 developers didn’t join in the discussions about “Perl 7” earlier this year, and in the podcast I’m specifically mentioned by name, I thought I’d go ahead and comment now and try to improve the record a bit.</p>
<p>While I can’t speak for the other Perl 6 developers, in my case I didn’t contribute to the discussion because nearly all the things I would’ve said were already being said better by others such as Larry, rjbs, mst, chromatic, etc.  I think a “Perl 7” rebrand is the wrong approach, for exactly the reasons they give.</p>
<p>A couple of statements  in the podcast refer to “hurting the feelings of Perl 6 developers” as being a problem resulting from a rebrand to Perl 7. I greatly appreciate that people are concerned with the possible impact of a Perl 5 rebrand on Perl 6 developers and our progress.  I believe that Perl 6’s success or failure at this point will have little to do with the fact that “6 is larger than 5”.  I don’t find the basic notion of “Perl 7” offensive or directly threatening to Perl 6.</p>
<p>But I fully agree with <a href="http://shadow.cat/blog/matt-s-trout/names-and-numbers/">mst</a> that “you can’t … have two successive numbers in two brands and not expect people to be confused.”  We already have problems explaining “5” and “6” — adding more small integers to the explanation would just make an existing problem even worse, and wouldn’t do anything to address the fundamental problems Perl 6 was intended to resolve.</p>
<p>Since respected voices in the community were already saying the things I thought about the name “Perl 7”, I felt that adding my voice to that chorus could only be more distracting than helpful to the discussion. My involvement would inject speculations on the motivations of Perl 6 developers into what is properly a discussion about how to promote progress with Perl 5.  I suspect that other Perl 6 developers independently arrived at similar conclusions and kept silent as well (Larry being a notable exception).</p>
<p>I’d also like to remark on a couple of @sharifulin’s comments in the podcast (acknowledging that the transcribed comments may be imprecise in the translation from Russian):</p>
<p>First, I’m absolutely not the “sole developer” of Perl 6 (13:23 in the podcast), or even the sole developer of Rakudo Perl 6.  Frankly I think it’s hugely disrespectful to so flippantly ignore the contributions of others in the Perl 6 development community.  Let’s put some actual facts into this discussion… in the past twelve months there have been over 6,500 commits from over 70 committers to the various Perl 6 related repositories (excluding module repositories), less than 4% (218) of those commits are from me. Take a look at the author lists from the Perl 6 commit logs and you may be a little surprised at some of the people you find listed there.</p>
<p>Second, there is not any sense in which I think that clicking “Like” on a Facebook posting could be considered “admitting defeat” (13:39 in the podcast). For one, my “Like” was actually liking rjbs’ reply to mst’s proposal, as correctly noted in the footnotes (thanks Peter!).</p>
<p>But more importantly, I just don’t believe that Perl 5 and Perl 6 are in a battle that requires there to be a conquerer, a vanquished, or an admission of defeat.</p>
<p>Pm</p>
</div>
    </content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">[This is a response to the Russian Perl Podcast transcribed by Peter Rabbitson and discussed at blogs.perl.org.] I found this translation and podcast to be interesting and useful, thanks to all who put it together. Since there seems to have been … <a href="http://pmthium.com/2013/06/a-perl-6-developers-reply-to-a-russian-perl-podcast/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>pmichaud</name>
    </author>
    <id>http://pmthium.com/?p=388</id>
    <published>2013-06-03T20:13:53Z</published>
    <updated>2013-06-03T20:13:53Z</updated>
    <category term="perl6"/>
    <category term="rakudo"/>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-1163079349106481731.post-2970753924328059732</id>
    <published>2013-05-06T02:43:00.000-07:00</published>
    <updated>2013-05-08T15:22:22.880-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="programming"/>
    <title type="text">Porting a Module to Perl 6</title>
    <content type="html">&lt;a href="http://search.cpan.org/"&gt;CPAN&lt;/a&gt; is a huge draw for Perl 5, with approximately umpteen zillion modules available for a wide arrangement of purposes.&amp;nbsp; It's probably the biggest draw for the Perl 5 language these days, given the newer, hipper scripting languages out there like Ruby, Python, and of course &lt;a href="http://www.intercaloninterstates.org/"&gt;INTERCAL&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The problem is, these modules are not yet usable in Perl 6 directly.&amp;nbsp; There is an ongoing project to allow &lt;a href="https://github.com/rakudo-p5/v5"&gt;Perl 5 code to run in Rakudo&lt;/a&gt;, but so far only the most basic code works: like basic loops, quite a few builtins, backticks, etc.&amp;nbsp; It does inherit from the Perl 6 object system, which is pretty cool, so &lt;code&gt;$foo-&amp;gt;WHAT&lt;/code&gt; can tell you if you have a &lt;code&gt;Str&lt;/code&gt;, &lt;code&gt;Int&lt;/code&gt;, or &lt;code&gt;IO::Handle&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
So for right now, the only practical way to use Perl 5 modules is to rewrite them in Perl 6.&amp;nbsp; I just finished porting the &lt;a href="https://github.com/FROGGS/p6-File-Spec"&gt;File::Spec module&lt;/a&gt;, one of Perl 5's core modules, to help deal with file paths on different operating systems. FROGGS++ did much of the initial work on it, but he's moved on the P5 in P6 project mentioned above, so I picked up the slack. The end goal of the project is for me to integrate functionality like Perl 5's Path::Class into the core language, so that OS interoperability comes naturally when using the native functions.&lt;br /&gt;
&lt;br /&gt;
As I got further into the port, I have been convinced that porting the module is a &lt;i&gt;much&lt;/i&gt; better choice than relying on the Perl 5 code being integrated.&amp;nbsp; There are several reasons for this:&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Code Cruft&lt;/h4&gt;
&lt;br /&gt;
There is a lot of support for operating systems that are now out of date.&amp;nbsp; This isn't a bad thing.&amp;nbsp; I'm sure that there's some hobbyist who will want to run Perl 6 on their OS/2 Warp system.&amp;nbsp; The problem comes when you look inside the code for the OS2 module:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $path =~ s/^([a-z]:)/\l$1/s;&lt;/code&gt;&lt;br /&gt;
This little no-op snippet from canonpath (to produce the canonically correct path) converts a lowercase drive letter to lowercase.&amp;nbsp; It's not harmful, but it does illustrate the fact that no one has edited this code in 9 years.&lt;br /&gt;
&lt;br /&gt;
This isn't the fault of the Perl 5 Porters -- they have plenty of better things to do than to support outdated OSes when not even bug tickets are coming in.&amp;nbsp; But translating the code sure gives a great opportunity to notice these problems.&lt;br /&gt;
&lt;br /&gt;
In the end, I ended up cutting the entire OS2 module and delegating to Win32.pm, because it had support for things like UNC paths (&lt;code&gt;//server/share&lt;/code&gt;) that OS2.pm had only half-implemented.&amp;nbsp; And so a huge block of code cruft bit the dust.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Readability and Maintainability&lt;/h4&gt;
&lt;br /&gt;
Part of the reason these issues happen in the first place is that it's harder to see what's going on in a given piece of code.&lt;br /&gt;
&lt;br /&gt;
An example I came across was in this helper for tmpdir, a method to return the first temporary directory that's writable in a list of parameters.&amp;nbsp; In Perl 5, we get:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;sub _tmpdir {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; my $self = shift;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; my @dirlist = @_;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; my $tmpdir;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (@dirlist) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; next unless defined &amp;amp;&amp;amp; -d &amp;amp;&amp;amp; -w _;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; $tmpdir = $_;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; last;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; return $self-&amp;gt;canonpath($tmpdir);&lt;br /&gt;
}&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
That's actually good, idiomatic code for Perl 5, though it can look like spooky action at a distance if you're not aware of what's going on with &lt;code&gt;$_&lt;/code&gt;, &lt;code&gt;@_&lt;/code&gt;, and &lt;code&gt;shift&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
Equivalent code in Perl 6 looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;method !tmpdir( *@dirlist ) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; my $tmpdir = first { .defined &amp;amp;&amp;amp; .IO.w &amp;amp;&amp;amp; .IO.d }, @dirlist;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; return self.canonpath($tmpdir);&lt;br /&gt;
}&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
No messing about with parameters and keeping track of the object -- it all happens in the signature.&amp;nbsp; You no longer have to read through a loop to understand the code either -- in Perl 6 you can just say that you want the first matching candidate, and first() will lazily test the list for you.&lt;br /&gt;
&lt;br /&gt;
The P6 version gets to the point much faster, and it's much closer to natural language: "set &lt;code&gt;$tmpdir&lt;/code&gt; to the first defined writable directory in &lt;code&gt;@dirlist&lt;/code&gt;."&amp;nbsp; Less, easier to read code is easier to maintain.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Changing Old Features&lt;/h4&gt;
&lt;br /&gt;
At some point, your code was working perfectly and passes all the tests.&amp;nbsp; But then the computer world changes around you, and it no longer makes any sense.&amp;nbsp; And you would like to refactor, but people rely on the old functionality.&lt;br /&gt;
&lt;br /&gt;
This is exactly what happened for File::Spec's case_tolerant function.&amp;nbsp; It essentially looks at the operating system alone, and uses that to determine if the filesystem is case-sensitive.&amp;nbsp; Which in the old days made perfect sense when Macs used HFS+, Windows used FAT, and Unix used ufs or a variant.&amp;nbsp; But my computer runs Mac OS X and Windows and has several drive partitions in different formats.&amp;nbsp; Heck, the NTFS drives are case sensitive in POSIX-land, but as soon as I boot Windows they become case insensitive.&lt;br /&gt;
&lt;br /&gt;
The only reasonable way to check this now is to actually check the filesystem for a specific directory, given widespread support for symlinks.&amp;nbsp; This breaks the old functionality.&amp;nbsp; But there's no time like a major language revision to break old APIs and replace them with shiny new ones.&lt;br /&gt;
&lt;br /&gt;
However, there are a couple of major downsides to porting:&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
This is really time-consuming&lt;/h4&gt;
&lt;br /&gt;
Sure, you don't have to implement the algorithm from scratch, and you have plenty of tests to help your development.&amp;nbsp; It would be possible to just translate the existing code, because things aren't that different.&amp;nbsp; Change an &lt;code&gt;if( $foo )&lt;/code&gt; to &lt;code&gt;if $foo&lt;/code&gt;, etc.&lt;br /&gt;
&lt;br /&gt;
However, a major reason for doing the porting is to use the Perl 6 idioms instead, especially in function declarations and regular expressions where it makes a major difference in code readability.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Dependencies aren't available&lt;/h4&gt;
&lt;br /&gt;
Sometimes your code relies on separate modules not available, or on not yet implemented functions.&amp;nbsp; Your choice becomes to either implement the functionality yourself and embark on yet another yak-shaving expedition, or mark it as todo and wait for the appropriate functionality to arrive.&lt;br /&gt;
&lt;br /&gt;
This has become a much smaller problem as of late as the core language matures.&amp;nbsp; But "done enough" is not really "done".&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;br /&gt;
Now that I've written this, I've realized that my own project is a microcosm of the Perl 6 saga.&amp;nbsp; Making a better codebase takes a lot of time, but it ultimately seems worth the effort.&lt;br /&gt;
&lt;br /&gt;
Of course, once I had gotten this far, I realized that File::Spec -- or something very much like it -- would be needed to implement IO::Path objects for non-unixlike OSes.&amp;nbsp; So stay tuned for the next part in this saga: How to add File::Spec to Rakudo.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Update&lt;/b&gt;: It ended up turning into two posts:&amp;nbsp; One was a simple guide on &lt;a href="http://blog.brentlaabs.com/2013/05/how-to-start-hacking-on-rakudo-perl-6.html"&gt;How to Start Hacking Rakudo Perl 6&lt;/a&gt;, and the other covered my follies in trying to add to the compiler for the first time.&amp;nbsp; But the short story is that IO::Path is now added to Perl 6 and &lt;a href="http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html"&gt;implemented in Rakudo&lt;/a&gt; -- this means that both File::Spec and Path::Class' behavior are now available in the core language without adding modules.</content>
    <link rel="replies" type="application/atom+xml" href="http://blog.brentlaabs.com/feeds/2970753924328059732/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://blog.brentlaabs.com/2013/05/porting-module-to-perl-6.html#comment-form" title="2 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/2970753924328059732"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/2970753924328059732"/>
    <link rel="alternate" type="text/html" href="http://blog.brentlaabs.com/2013/05/porting-module-to-perl-6.html" title="Porting a Module to Perl 6"/>
    <author>
      <name>Brent Laabs</name>
      <uri>http://www.blogger.com/profile/17518100165641296059</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>2</thr:total>
  </entry>
  <entry xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0">
    <id>tag:blogger.com,1999:blog-1163079349106481731.post-4113144105883499844</id>
    <published>2013-05-08T01:39:00.000-07:00</published>
    <updated>2013-05-08T01:40:00.066-07:00</updated>
    <category scheme="http://www.blogger.com/atom/ns#" term="howto"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="perl6"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="programming"/>
    <title type="text">How to start hacking on Rakudo Perl 6</title>
    <content type="html">In the course of writing modules, I finally got the urge to start implementing features I wanted in Rakudo itself.&amp;nbsp; And since there wasn't a real guide on how to set up and patch Rakudo, I decided to share what I had learned in the process.&lt;br /&gt;
&lt;br /&gt;
The nice thing about Perl 6 implementations is that as significant portion of them is written in Perl 6.&amp;nbsp; (Well, one nice thing anyway.)&amp;nbsp; This means that if you're comfortable writing Perl 6 modules and classes, you should feel pretty much at home in the source.&lt;br /&gt;
&lt;br /&gt;
This guide assumes so, and that you have a basic familiarity with Github, &lt;code&gt;git&lt;/code&gt;, and &lt;code&gt;make&lt;/code&gt; -- enough to commit to repositories and build a software package, anyway.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Getting Started&lt;/h3&gt;
This first thing is to get your own branch of Rakudo to work on.&amp;nbsp; So go to the &lt;a href="https://github.com/rakudo/rakudo"&gt;Rakudo repository&lt;/a&gt; and click the fork button in the upper right.&amp;nbsp; Relax while Github &lt;a href="https://assets.github.com/images/spinners/hardcore-forking.gif"&gt;photocopies a book&lt;/a&gt;.&amp;nbsp; Once that's done, find an appropriate directory to &lt;code&gt;git clone&lt;/code&gt; it to on your own machine.&lt;br /&gt;
&lt;br /&gt;
Go ahead and cd into the new &lt;code&gt;rakudo&lt;/code&gt; directory.&amp;nbsp; There are a few setup things that you'll want to do.&amp;nbsp; First of all, go ahead and build Rakudo, using the normal steps:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; perl ./Configure.pl --gen-parrot&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; make&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; make install&lt;/code&gt;&lt;br /&gt;
That will pull a copy of NQP and Parrot, and make sure that everything is working okay to begin with.&amp;nbsp; Now that that's done, you'll want to add the new perl6 to your system &lt;code&gt;$PATH&lt;/code&gt; environment variable.&amp;nbsp;&amp;nbsp; Which, if you don't know how to do it -- well &lt;a href="https://www.google.com/search?q=how+do+i+add+to+path+environment"&gt;here's Google&lt;/a&gt;.&amp;nbsp; In particular, you'll need to add the full path to the &lt;code&gt;rakudo/install/bin&lt;/code&gt; directory.&lt;br /&gt;
&lt;br /&gt;
There's a couple more things you'll want to do now.&amp;nbsp; First of all:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; make spectest&lt;/code&gt;&lt;br /&gt;
You don't have to run the full tests now, but let it download the roast repository into your &lt;code&gt;t/spec&lt;/code&gt; before hitting ^C.&amp;nbsp; You will need these tests later to make sure you didn't break anything.&lt;br /&gt;
&lt;br /&gt;
Next, you'll want to set up a link back to the main Rakudo repository, so you can pull changes from there.&amp;nbsp; So do:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; git remote add upstream git://github.com/rakudo/rakudo.git&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
You'll also want the module installer, Panda.&amp;nbsp; Now, obviously, you shouldn't add anything to Rakudo that depends on an outside module.&amp;nbsp; But Panda is the one piece of software you really don't want to break, ever.&amp;nbsp; People will still want to be able to download modules even if functionality changes.&amp;nbsp; We will have to go through a deprecation cycle if you intentionally change something to cause Panda to start failing its tests.&amp;nbsp; So to download and install it:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; git clone git://github.com/tadzik/panda.git&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; cd panda&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; perl6 bootstrap.pl&lt;/code&gt;&lt;br /&gt;
This will set up Panda's dependencies, and test all of those modules.&amp;nbsp; The bootstrap script will tell you a path to add to your $PATH environment variable -- add it too, so that panda will run from anywhere.&lt;br /&gt;
&lt;br /&gt;
Finally, you really should set up a new branch to work on, so you can switch back to a working Rakudo if you need to.&amp;nbsp; Move back into the rakudo directory and run:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; git checkout -b mynewbranchname&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
A very short overview of the source&lt;/h3&gt;
&lt;br /&gt;
Now that all the setup is done, let's take a quick look around.&amp;nbsp; Most of what we build into Perl 6 lives in the &lt;code&gt;rakudo/src&lt;/code&gt; folder, so this is where you'll want to edit the contents.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;vm&lt;/code&gt; directory contains files specific to the virtual machines Rakudo runs under.&amp;nbsp; At this time of this writing, there's only one thing in there, &lt;code&gt;parrot&lt;/code&gt;, but very soon there will also be a &lt;code&gt;jvm&lt;/code&gt; directory.&amp;nbsp; Exciting!&amp;nbsp; Most of the purpose of this code is to map functions to lower-level operations, in either Parrot or Java.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Perl6&lt;/code&gt; directory contains the grammar and actions used to build the language, as well as the object metamodel.&amp;nbsp; The contents of this folder are written in NQP, or Not Quite Perl.&amp;nbsp; This section determines how the language is parsed.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;core&lt;/code&gt; directory contains the files that will be built into the core setting.&amp;nbsp; You'll find classes or subroutines in here for just about everything in Perl: strings, operators like &lt;code&gt;eq&lt;/code&gt;, filehandles, sets, and more.&amp;nbsp; Individual files look similar to modules, but these are "modules" that are available to every Perl 6 program.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;gen&lt;/code&gt; directory contains files that are created in the compliation process.&amp;nbsp; The core setting lives here, creatively named &lt;code&gt;CORE.setting&lt;/code&gt;.&amp;nbsp; And if you look at it, it's just a concatenation of the files in &lt;code&gt;core&lt;/code&gt;, put together in the order specified in &lt;code&gt;rakudo/tools/build/Makefile.in&lt;/code&gt;.&amp;nbsp; While these files can and do get overwritten in the build process, it's often a good idea to keep a copy of CORE.setting open so you can find what you're looking for faster -- and then go edit it in &lt;code&gt;core&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;
Let's start hacking!&lt;/h3&gt;
&lt;br /&gt;
Now's the time to start changing Rakudo.&amp;nbsp; Have the appropriate amount of fun!&amp;nbsp; Be sure to commit functioning changes occasionally, so that you can &lt;code&gt;git bisect&lt;/code&gt; for problems later.&amp;nbsp; And push your edits to Github as a free backup.&amp;nbsp; If you get stuck, drop by #perl6 on irc.freenode.net and ask questions.&lt;br /&gt;
&lt;br /&gt;
If it's your first time, you have to fi^W^W^W^W you will probably make a lot of mistakes.&amp;nbsp; I know I did on my first project, as &lt;a href="http://blog.brentlaabs.com/2013/05/implementing-iopath-in-rakudo.html"&gt;explained in detail&lt;/a&gt; in a previous post.&amp;nbsp;&amp;nbsp; But I promise you, the learning curve is surprisingly easy, and your compiler-fu will increase to fuchsia-belt level in no time.&amp;nbsp; (What?&amp;nbsp; We're not just giving black belts away... and Camelia likes fuchsias.) &lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Testing and Specs&lt;/h3&gt;
&lt;br /&gt;
When you think you're finished with your code, the first thing you should do is merge in the upstream rakudo, and rebuild:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; git fetch upstream&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; git merge upstream/nom&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; perl Configure.pl&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; make&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; make spectest&lt;/code&gt;&lt;br /&gt;
The spectests will make sure that you didn't accidentally break the codebase.&amp;nbsp; You should pass, or at least not fail worse than the &lt;a href="https://github.com/coke/perl6-roast-data"&gt;current roast data&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
You should add your own tests into the &lt;a href="https://github.com/perl6/roast/"&gt;roast repository&lt;/a&gt; about now.&amp;nbsp; You do have unit tests, right?&amp;nbsp;&amp;nbsp; Writing tests is "optional", just like brushing your teeth -- you don't have to do it, but if you never do it you're in for a lot of pain later.&amp;nbsp; Here's a fine and elegantly crafted hyperlink to &lt;a href="http://perlcabal.org/syn/S24.html"&gt;S24 (Testing)&lt;/a&gt; for reference. &lt;br /&gt;
&lt;br /&gt;
When editing a file that already exists in roast, you may need to fudge the tests for Niecza and Pugs.&amp;nbsp; This tells us "we know the test failed or fails to parse, nothing has changed".&amp;nbsp; Just add lines like the following above broken tests:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #?pugs 1 skip 'reason'&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; #?niecza 1 skip 'reason'&lt;/code&gt;&lt;br /&gt;
The "1" is actually the number of tests you want to skip, but really, look at the README in roast for more details.&lt;br /&gt;
&lt;br /&gt;
If you want to add a whole new test file, you'll need to add it into &lt;code&gt;rakudo/t/spectest.data&lt;/code&gt;.&amp;nbsp; If your code fixes broken tests, then you'll want to *unfudge* by removing the &lt;code&gt;#?rakudo skip&lt;/code&gt; lines above the relevant tests.&lt;br /&gt;
&lt;br /&gt;
You should also test that Panda is still working.&amp;nbsp; Since you'll have to rebuild panda after recompling Rakudo anyway, just check the rebootstrap for test failures:&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; perl6 panda/rebootstrap.pl&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Commiting to Rakudo&lt;/h3&gt;
&lt;br /&gt;
The easiest way to get your code merged is to push it back to Github, and then send a pull request into Rakudo.&amp;nbsp; If you're really committed to committing, consider sending in a &lt;a href="http://www.perlfoundation.org/legal"&gt;Contributor License Agreement&lt;/a&gt; to The Perl Foundation.&amp;nbsp; This makes you eligible for a commit bit to push directly to the Rakudo repo.&lt;br /&gt;
&lt;br /&gt;
If there's a problem, someone will get back to you pretty fast on the Github issues page.&amp;nbsp; Hopefully, these problems will be easy to fix, and a standard &lt;code&gt;git commit; git push&lt;/code&gt; will add it to the ticket.&amp;nbsp; If there aren't any problems, someone will just merge it in a couple days.&lt;br /&gt;
&lt;br /&gt;
Huzzah! \o/&amp;nbsp; A Rakudo Hacker is you!</content>
    <link rel="replies" type="application/atom+xml" href="http://blog.brentlaabs.com/feeds/4113144105883499844/comments/default" title="Post Comments"/>
    <link rel="replies" type="text/html" href="http://blog.brentlaabs.com/2013/05/how-to-start-hacking-on-rakudo-perl-6.html#comment-form" title="2 Comments"/>
    <link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/4113144105883499844"/>
    <link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/1163079349106481731/posts/default/4113144105883499844"/>
    <link rel="alternate" type="text/html" href="http://blog.brentlaabs.com/2013/05/how-to-start-hacking-on-rakudo-perl-6.html" title="How to start hacking on Rakudo Perl 6"/>
    <author>
      <name>Brent Laabs</name>
      <uri>http://www.blogger.com/profile/17518100165641296059</uri>
      <email>noreply@blogger.com</email>
      <gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="https://img1.blogblog.com/img/b16-rounded.gif"/>
    </author>
    <thr:total>2</thr:total>
  </entry>
  <entry>
    <title>A Rakudo Performance</title>
    <link rel="alternate" href="http://pmthium.com/2012/09/a-rakudo-performance/" type="text/html"/>
    <content type="html">&lt;p&gt;At YAPC::NA 2012 in Madison, WI I gave a &lt;a href="http://en.wikipedia.org/wiki/Lightning_talk"&gt;lightning talk&lt;/a&gt; about basic improvements in Rakudo&amp;#8217;s performance over the past couple of years.  Earlier today the &lt;a href="http://www.youtube.com/watch?v=ILWrbvI8Qfg"&gt;video&lt;/a&gt; of the &lt;a href="http://act.yapcna.org/2012/talk/22"&gt;lightning talks session&lt;/a&gt; appeared on YouTube; I&amp;#8217;ve clipped out my talk from the session into a separate video below.  Enjoy!&lt;/p&gt;
&lt;p&gt;&lt;iframe width="640" height="480" src="http://www.youtube.com/embed/tCel6lpDTZI?feature=oembed" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">At YAPC::NA 2012 in Madison, WI I gave a lightning talk about basic improvements in Rakudo’s performance over the past couple of years.  Earlier today the video of the lightning talks session appeared on YouTube; I’ve clipped out my talk … <a href="http://pmthium.com/2012/09/a-rakudo-performance/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>pmichaud</name>
    </author>
    <id>http://pmthium.com/?p=265</id>
    <published>2012-09-02T23:00:26Z</published>
    <updated>2012-09-02T23:00:26Z</updated>
    <category term="perl6"/>
    <category term="rakudo"/>
  </entry>
  <entry>
    <title>Roborama 2012a</title>
    <link rel="alternate" href="http://pmthium.com/2012/05/roborama-2012a/" type="text/html"/>
    <content type="html">&lt;p&gt;A couple of weeks ago I entered the &lt;a href="http://www.dprg.org/"&gt;Dallas Personal Robotics Group&lt;/a&gt; &lt;a href="http://www.dprg.org/competitions/roborama2012a/"&gt;Roborama 2012a competition&lt;/a&gt;, and managed to come away with first place in the RoboColumbus event and Line Following event (Senior Level).  For my robot I used one of the &lt;a href="http://mindstorms.lego.com/"&gt;LEGO Mindstorms&lt;/a&gt; sets that we&amp;#8217;ve been acquiring for use by our &lt;a href="http://modelscoutrobotics.org/"&gt;First Lego League team&lt;/a&gt;, along with various 3rd party sensors.&lt;/p&gt;
&lt;p&gt;The goal of the RoboColumbus event was to build a robot that could navigate from a starting point to an ending point placed as far apart as possible; robots are scored on distance to the target when the robot stops.  If multiple robots touch the finish marker (i.e., distance zero), then the time needed to complete the course determines the rankings.   This year&amp;#8217;s event was in a long hall with the target marked by an orange traffic cone.&lt;/p&gt;
&lt;div id="attachment_240" style="width: 310px" class="wp-caption alignright"&gt;&lt;a href="http://pmthium.com/wp/wp-content/uploads/2012/05/img-20120528-002134.jpg"&gt;&lt;img class="size-medium wp-image-240" title="img-20120528-002134" src="http://pmthium.com/wp/wp-content/uploads/2012/05/img-20120528-002134-300x225.jpg" alt="HiTechnic IR ball and IRSeeker" width="300" height="225" srcset="http://pmthium.com/wp/wp-content/uploads/2012/05/img-20120528-002134-300x225.jpg 300w, http://pmthium.com/wp/wp-content/uploads/2012/05/img-20120528-002134-200x150.jpg 200w, http://pmthium.com/wp/wp-content/uploads/2012/05/img-20120528-002134-640x480.jpg 640w, http://pmthium.com/wp/wp-content/uploads/2012/05/img-20120528-002134.jpg 721w" sizes="(max-width: 300px) 100vw, 300px" /&gt;&lt;/a&gt;&lt;p class="wp-caption-text"&gt;HiTechnic IR ball and IRSeeker sensor&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;Contestants are allowed to make minor modifications to the course to aid navigation, so I equipped my robot with a &lt;a href="http://www.hitechnic.com/cgi-bin/commerce.cgi?preadd=action&amp;amp;key=NSK1042"&gt;HiTechnic IRSeeker sensor&lt;/a&gt; and put an &lt;a href="http://www.hitechnic.com/cgi-bin/commerce.cgi?preadd=action&amp;amp;key=IRB1005"&gt;infrared (IR) electronic ball&lt;/a&gt; on top of the traffic cone.  The IRSeeker sensor reports the relative direction to the ball (in multiples of 30 degrees), so the robot simply traveled forward until the sensor picked up the IR signal, then used the IR to home in on the traffic cone.  You can see the results of the winning run in the video below, especially around the 0:33 mark when the robot makes its first significant IR correction:&lt;/p&gt;
&lt;p&gt;http://youtu.be/x1GvpYAArfY&lt;/p&gt;
&lt;p&gt;My first two runs of RoboColumbus didn&amp;#8217;t do nearly as well; the robot kept curving to the right for a variety of reasons, and so it never got a lock on the IR ball.  Some quick program changes at the contest and adjustments to the starting direction finally made for the winning run.&lt;/p&gt;
&lt;p&gt;For the Line Following contest, the course consisted of white vinyl tiles with electrical tape in various patterns, including line gaps and sharp angles.  I used a &lt;a href="http://mindsensors.com/index.php?module=pagemaster&amp;amp;PAGE_user_op=view_page&amp;amp;PAGE_id=111"&gt;LineLeader sensor&lt;/a&gt; from &lt;a href="http://mindsensors.com/"&gt;mindsensors.com&lt;/a&gt; for basic line following, with some heuristics for handling the gap conditions.  The robot performed fine on my test tiles at home, but had difficulty with the &amp;#8220;gap S curve&amp;#8221; tiles used at the contest.  However, my robot was the only one that successfully navigated the right angle turns, so I still ended up with first place.  &lt;img src="https://s.w.org/images/core/emoji/2.2.1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;iframe width="640" height="360" src="http://www.youtube.com/embed/BF1ElplYi74?feature=oembed" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;Matthew and Anthony from our &lt;a href="http://modelscoutrobotics.org/"&gt;FLL robotics team&lt;/a&gt; also &lt;a href="http://modelscoutrobotics.org/roborama2012a/"&gt;won other events&lt;/a&gt; in the contest, and there are &lt;a href="http://www.youtube.com/playlist?list=PL99FB10840A82C950"&gt;more&lt;/a&gt; &lt;a href="http://www.youtube.com/playlist?list=PL50F30261D8CDCAC5"&gt;videos&lt;/a&gt; and &lt;a href="http://www.flickr.com/photos/steevithak/sets/72157629871605390/"&gt;photos&lt;/a&gt; available.  The contest was a huge amount of fun and I&amp;#8217;m already working on new robot designs for the next competition.&lt;/p&gt;
&lt;p&gt;Many thanks to DPRG and the contest sponsors for putting on a great competition!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
</content>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">A couple of weeks ago I entered the Dallas Personal Robotics Group Roborama 2012a competition, and managed to come away with first place in the RoboColumbus event and Line Following event (Senior Level).  For my robot I used one of … <a href="http://pmthium.com/2012/05/roborama-2012a/">Continue reading <span class="meta-nav">→</span></a></div>
    </summary>
    <author>
      <name>pmichaud</name>
    </author>
    <id>http://pmthium.com/?p=239</id>
    <published>2012-05-28T06:08:52Z</published>
    <updated>2012-05-28T06:08:52Z</updated>
    <category term="lego"/>
    <category term="robotics"/>
    <category term="dprg"/>
    <category term="roborama"/>
  </entry>
</feed>
