<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Davide Lettieri Blog</title>
        <link>https://davidelettieri.it/</link>
        <description>Davide Lettieri Blog</description>
        <lastBuildDate>Mon, 06 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Lox as a Racket language module]]></title>
            <link>https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module</link>
            <guid>https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module</guid>
            <pubDate>Mon, 06 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[For a long time, I wanted to implement a Racket language module with a non-lispy surface syntax. Lox, from Crafting Interpreters, was an obvious candidate: I didn't want to invent a new syntax nor new semantics and I already ported the project to C#. In this case, my main objective was to leverage Racket language-building facilities while learning Racket, Scheme, and macros.]]></description>
            <content:encoded><![CDATA[<p>For a long time, I wanted to implement a Racket language module with a non-lispy surface syntax. Lox, from <a href="https://craftinginterpreters.com/" target="_blank" rel="noopener noreferrer" class="">Crafting Interpreters</a>, was an obvious candidate: I didn't want to invent a new syntax nor new semantics and I already ported the project to C#. In this case, my main objective was to leverage Racket language-building facilities while learning Racket, Scheme, and macros.</p>
<p><a class="" href="https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module">I attempted this already a few years ago, with little success</a>. This time I dropped yacc and lex libraries and instead followed the approach from the book more closely, along with the C# version I had written earlier. The result is not especially functional in style: the scanner and parser are fairly imperative and rely on mutation, mainly because that made the code easier to port from the earlier implementations.
Another big help came from LLMs, I used GitHub Copilot and it helped me fill some gaps in my knowledge and troubleshoot issues that I honestly didn't have enough competencies to solve.</p>
<p>I do not use GitHub Copilot autocomplete because that removes all the fun from coding but I "chatted" extensively and I also asked it to generate parts I was not particularly interested in, such as the colorer<sup><a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#user-content-fn-1-36a7e0" id="user-content-fnref-1-36a7e0" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetStickyNavbar_Vzrq">1</a></sup>.</p>
<p>The code is available on GitHub <a href="https://github.com/davidelettieri/racket-lox" target="_blank" rel="noopener noreferrer" class="">here</a>. In the post I'll go through the implementation, highlighting all the parts that I consider interesting or helpful.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="implementation-strategy">Implementation strategy<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#implementation-strategy" class="hash-link" aria-label="Direct link to Implementation strategy" title="Direct link to Implementation strategy" translate="no">​</a></h2>
<p>The objective of the project is to have a Lox implementation as a Racket language module. For me, that means passing all tests from the Crafting Interpreter repo up to Chapter 13. The original implementation repo provides a Dart script to execute the test suite against any interpreter:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">dart tool/bin/test.dart chap13_inheritance </span><span class="token parameter variable" style="color:#36acaa">--interpreter</span><span class="token plain"> racket</span><br></span></code></pre></div></div>
<p>In order to have this working I added the <code>#lang racket-lox</code> at the top of each test file and changed the expected line adding 1. This approach is effective once you have a "working" language module already in place. For this reason, the first few steps of the implementation have been done without "validation". I wrote a stub of the scanner, the parser and the language expansion. Once I was able to run the tests the development loop was pretty nice. I added a few unit tests to confirm some behaviors and iterate quicker on some bits of the implementation.</p>
<p>The implementation is validated at multiple levels:</p>
<ul>
<li class="">pass the <code>chap13_inheritance</code> test suite from the book</li>
<li class="">major part of the implementation, scanner, parser and resolver have unit tests</li>
<li class="">there are a few runtime unit tests</li>
</ul>
<p>The final implementation passes all the relevant Lox tests and all the unit tests added to the repo. However, this doesn't mean that all edge case is necessarily correct. For example, a Gemini review surfaced an issue in the evaluation of -(-0.0) that neither the original Lox tests nor my own tests caught.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="defining-the-racket-lox-language">Defining the racket-lox language<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#defining-the-racket-lox-language" class="hash-link" aria-label="Direct link to Defining the racket-lox language" title="Direct link to Defining the racket-lox language" translate="no">​</a></h3>
<p>As a language-oriented programming language, Racket provides all the facilities needed to build custom programming languages. This means having to build 2 different pieces:</p>
<ul>
<li class="">An expander module</li>
<li class="">A reader module</li>
</ul>
<p>The expander module is the first module to be imported and it contains all the bindings that will be available. In particular there is an implicit form <code>#%module-begin</code> that must be provided, a few that can be provided such as <code>#%top</code> or <code>#%datum</code>. The reader module is responsible for reading the program text and converting it into Racket code. If the surface syntax is lisp-like there are additional facilities to help with the definition of the language.</p>
<p>To make a comparison between Lox implementation pieces and racket-lox parts we can say:</p>
<ul>
<li class="">scanner, both Lox and racket-lox have a scanner. Behavior is almost the same, racket-lox scanner returns a list of tokens (plus errors if any).</li>
<li class="">parser, both Lox and racket-lox have a parser. Behavior is different, racket-lox parser returns racket syntax objects. There is no pre-defined AST with classes.</li>
<li class="">interpreter, racket-lox does not have an interpreter. The language is not interpreted, a <code>lox.rkt</code> file contains macros and functions that replicates Lox behavior in Racket.</li>
<li class="">resolver, both Lox and racket-lox have a resolver. The behavior is different, Lox resolver is executed at runtime before passing the AST to the interpreter. In racket-lox, the resolver is executed at compile time. Its responsibilities are to forbid:<!-- -->
<ul>
<li class="">invalid top-level <code>return</code></li>
<li class="">returning a value from <code>init</code></li>
<li class="">invalid <code>this</code> usage</li>
<li class="">invalid <code>super</code> usage</li>
<li class="">class inheriting from itself</li>
<li class="">reading a local variable in its own initializer</li>
<li class="">duplicate local declarations in the same scope</li>
</ul>
</li>
<li class="">resolve-redefinitions. This is only in racket-lox, I used it to support variable re-definition in a top-level scope.</li>
<li class="">all "infrastructure" for supporting racket language modules like the reader, colorer, etc. is obviously only in racket-lox. The reader is necessary</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-verify-that-resolver-is-executed-at-compile-expansion-time">How to verify that resolver is executed at compile (expansion time)<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#how-to-verify-that-resolver-is-executed-at-compile-expansion-time" class="hash-link" aria-label="Direct link to How to verify that resolver is executed at compile (expansion time)" title="Direct link to How to verify that resolver is executed at compile (expansion time)" translate="no">​</a></h4>
<p>Execute the following code</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Source file proving that resolver is executed at compile time</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">#lang racket-lox</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">print "before";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">this;</span><br></span></code></pre></div></div>
<p>and the output will be:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Output</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[line 3] Error at 'this': Can't use 'this' outside of a class.</span><br></span></code></pre></div></div>
<p>Since there is no <code>before</code> printed anywhere we know the resolver is executed before the code from the source file is executed.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-resolve-redefinitions">What is resolve-redefinitions<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#what-is-resolve-redefinitions" class="hash-link" aria-label="Direct link to What is resolve-redefinitions" title="Direct link to What is resolve-redefinitions" translate="no">​</a></h4>
<p>Lox supports variable re-definition in a top-level scope, in order to support that I defined a function to be executed at expansion time <code>resolve-redefinitions</code>. In order to have it available at expansion time I wrapped the definition in a <code>begin-for-syntax</code>. The function is going through all the top-level statements received from the parser and:</p>
<ul>
<li class="">it keeps track of defined variables</li>
<li class="">it replaces a <code>lox-var-declaration</code> with a <code>lox-assign</code> whenever we are re-defining an existing variable.
Please note that the function does not need to be recursive because we are interested in rewriting only the top-level statements.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-custom-module-begin-form">The custom #%module-begin form<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#the-custom-module-begin-form" class="hash-link" aria-label="Direct link to The custom #%module-begin form" title="Direct link to The custom #%module-begin form" translate="no">​</a></h4>
<p>The racket-lox language uses a custom <code>#%module-begin</code> form for multiple reasons:</p>
<ul>
<li class="">we want to execute <code>resolve-statements</code> to enforce Lox language scoping rules.</li>
<li class="">we want to execute <code>resolve-redefinitions</code> to allow top-level variable re-declaration.</li>
<li class="">we want to use <code>#%plain-module-begin</code> because the default <code>#%module-begin</code> prints out expression values to the default output port.</li>
</ul>
<p>In order to make <code>resolve-statements</code> work we need to pass it the un-expanded syntax tree produced by the reader. However Racket might pre-expand some forms before passing it to the language custom module. To avoid that we wrap the list of statements produced by the reader with a <code>lox-module-wrapper</code> which is doing nothing, it wraps everything in a <code>(begin ...)</code> and which we are removing in with the <code>unwrap-forms</code> function if we received it un-expanded. If racket is deciding to "pre-expand" something before passing it to our module, it will only expand the wrapper and not the inner forms. In this way the resolver will encounter the expected forms and work as intended.</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">racket-lox custom #%module-begin</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> custom-module-begin</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parser</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> form ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> raw-forms </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">unwrap-forms</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">form ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">resolve-statements</span><span class="token plain"> raw-forms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">fixed-forms</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">resolve-redefinitions</span><span class="token plain"> raw-forms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">#%plain-module-begin</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          fixed-forms ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-reader">The reader<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#the-reader" class="hash-link" aria-label="Direct link to The reader" title="Direct link to The reader" translate="no">​</a></h4>
<p>The reader is a required part of a Racket custom language. Its job is to implement <code>read-syntax</code> and <code>read</code>, both functions are returning a Racket module. Quoting from <a href="https://docs.racket-lang.org/guide/Module_Syntax.html" target="_blank" rel="noopener noreferrer" class="">Racket documentation</a>:</p>
<blockquote>
<p>The <code>#lang</code> at the start of a module file begins a shorthand for a module form, much like ' is a shorthand for a quote form.</p>
</blockquote>
<p>and</p>
<blockquote>
<p>The longhand form of a module declaration, which works in a REPL as well as a file, is</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">module</span><span class="token plain"> name-id initial-module-path</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> decl ...</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
</blockquote>
<p>This is exactly what our reader is doing:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">read-syntax</span><span class="token plain"> src in</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> source </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">or</span><span class="token plain"> src </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">object-name</span><span class="token plain"> in</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> tokens </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">scan-tokens</span><span class="token plain"> in</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> ast </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">parse</span><span class="token plain"> tokens</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> module-datum</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    `</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">module anonymous-module racket-lox</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-module-wrapper</span><span class="token plain"> ,@ast</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">datum-&gt;syntax</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> module-datum </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">list</span><span class="token plain"> source </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">read</span><span class="token plain"> in</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">read-syntax</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> in</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>Let's briefly look at the highlighted lines:</p>
<ol>
<li class="">The module definition uses <code>racket-lox</code> as its initial module. This means that all exported definitions in the package are available to the final module. We need it because we want to use macros and functions defined in <code>lox.rkt</code></li>
<li class="">We introduce here the <code>lox-module-wrapper</code>, as discussed previously we need it so that our resolver works correctly.</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="scanner">Scanner<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#scanner" class="hash-link" aria-label="Direct link to Scanner" title="Direct link to Scanner" translate="no">​</a></h2>
<p>The scanner mainly exposes the scan-tokens function and a few custom structs. scan-tokens takes an <a href="https://docs.racket-lang.org/guide/i_o.html" target="_blank" rel="noopener noreferrer" class="">input port</a> and walks through the source code. Its result is a scanner-output value containing both the tokens and an error flag. In the book’s implementation, scanner errors are reported through a static method on the interpreter. Since I do not have an interpreter here, I return that information explicitly instead.</p>
<p>Given the imperative style of the implementation, I also defined a <code>while</code> macro to use in loops and to closely mimic the book implementation. This macro is used also in the language expansion as well. Nothing fancy, there are plenty of examples online about this.</p>
<p>Something that resembles functional programming or at least more in line with Racket style, is the usage of <a href="https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Flist%29%29" target="_blank" rel="noopener noreferrer" class=""><code>for/list</code></a> in conjunction with <a href="https://docs.racket-lang.org/reference/sequences.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._in-producer%29%29" target="_blank" rel="noopener noreferrer" class=""><code>in-producer</code></a>. At the beginning I was using my <code>while</code> macro or a loop and using <code>cons</code> to build up lists of objects and then reversing the list to get the correct order. This was ugly as hell and doing the reverse at the end was painful.</p>
<p>The <code>for/list</code> has options to stop the collection of items, skip items, etc. The <code>in-producer</code> is a lazily evaluated, possibly infinite, sequence of items provided by a <code>producer</code> function.</p>
<p>Overall the implementation is quite straightforward.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="parser">Parser<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#parser" class="hash-link" aria-label="Direct link to Parser" title="Direct link to Parser" translate="no">​</a></h2>
<p>The parser resembles, as the scanner, the source implementation. I didn't define a class to hold the state, so I had two options:</p>
<ol>
<li class="">Pass the state around as parameter.</li>
<li class="">Use nested function definitions and capture the state from the outer context.
I chose the latter. It behaves almost like having an object instance whose methods access private fields, and it keeps the function signatures simpler because I do not have to pass the state around everywhere.</li>
</ol>
<p>I don't have a proper syntax tree with pre-defined types, the parser is producing a "lisped" version of Lox syntax. Style is mixed, I'm using <code>for/list</code> and <code>in-producer</code> like in the scanner but also more imperative constructs as my <code>while</code> macro, hand-written loops and such things.</p>
<p>Thanks to the macro support, I was able to extract some repetitive logic that appears when parsing <a href="https://craftinginterpreters.com/appendix-i.html#expressions" target="_blank" rel="noopener noreferrer" class="">expressions</a>:</p>
<div class="language-title='Part language-title='part codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-title='part codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">logic_or       → logic_and ( "or" logic_and )* ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">logic_and      → equality ( "and" equality )* ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">equality       → comparison ( ( "!=" | "==" ) comparison )* ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">comparison     → term ( ( "&gt;" | "&gt;=" | "&lt;" | "&lt;=" ) term )* ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">term           → factor ( ( "-" | "+" ) factor )* ;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">factor         → unary ( ( "/" | "*" ) unary )* ;</span><br></span></code></pre></div></div>
<p>All these productions have a similar form, they are all binary expressions:</p>
<ol>
<li class="">They depend on another production</li>
<li class="">They have a set of tokens for separating inner productions</li>
</ol>
<p>With that in mind I defined the following macro and all the expressions:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Macro for parsing binary ops</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">define-syntax-rule</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">iterative-production</span><span class="token plain"> name production . token-types</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> expr </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">production</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">while</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">match</span><span class="token plain"> .</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            token-types</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> op </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">previous</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> right </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">production</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> op-type </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">token-type</span><span class="token plain"> op</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">set!</span><span class="token plain"> expr </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">datum-&gt;syntax</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> `</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-binary ,expr ,op-type ,right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">token-&gt;src</span><span class="token plain"> op</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">iterative-production</span><span class="token plain"> factor unary </span><span class="token symbol" style="color:#36acaa">'SLASH</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'STAR</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">iterative-production</span><span class="token plain"> term factor </span><span class="token symbol" style="color:#36acaa">'MINUS</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'PLUS</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">iterative-production</span><span class="token plain"> or-syntax and-syntax </span><span class="token symbol" style="color:#36acaa">'OR</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">iterative-production</span><span class="token plain"> and-syntax equality </span><span class="token symbol" style="color:#36acaa">'AND</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">iterative-production</span><span class="token plain"> equality comparison </span><span class="token symbol" style="color:#36acaa">'BANG_EQUAL</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'EQUAL_EQUAL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">iterative-production</span><span class="token plain"> comparison term </span><span class="token symbol" style="color:#36acaa">'GREATER</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'GREATER_EQUAL</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'LESS</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'LESS_EQUAL</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>As in other parts of the code, a lot of imperative pieces such as the <code>while</code> loop and the <code>set!</code> to "accumulate" the result into the <code>expr</code> variable.</p>
<p>Another interesting part is the <code>assignment</code> production, <a href="https://github.com/davidelettieri/Lox" target="_blank" rel="noopener noreferrer" class="">here is my C# version</a>:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Assignment parsing in my C# implementation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token return-type class-name">IExpr</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Assignment</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> expr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Or</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">Match</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">EQUAL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> equals </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Previous</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">value</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Assignment</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token class-name">Variable</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Assign</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">v</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">case</span><span class="token plain"> </span><span class="token class-name">Get</span><span class="token plain"> g</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">g</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Obj</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> g</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">default</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token function" style="color:#d73a49">Error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">equals</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Invalid assignment target."</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">break</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> expr</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>In <code>C#</code> and in <code>Java</code> we can check if an object is of a specific type and cast it to the desired type. Given that I don't have any types but only Racket expressions produced by the parser I can't follow that approach. However, by knowing a bit of macros which are essentially functions with signature <code>syntax -&gt; syntax</code> bound to a given name, we can define a <code>syntax -&gt; syntax</code> function to understand what we have and react accordingly. The type check on the <code>expr</code> variable is replaced with a <code>syntax-parse</code> that is able to recognize the shape of the syntax we are expecting and produce the desired output syntax (opposed to a new AST object from Lox original implementation). The <code>#:datum-literals (lox-variable lox-get)</code> is telling <code>syntax-parse</code> that those elements need to be matched literally. Those are not pattern variables as <code>name:expr</code> or <code>obj:expr</code>:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Assignment syntax parser</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">assignment</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> expression </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">or-syntax</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">when</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">match</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'EQUAL</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> equal </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">previous</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> value </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">assignment</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">value</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">set!</span><span class="token plain"> expression</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> expression</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            #:datum-literals </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-variable</span><span class="token plain"> lox-get</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-variable</span><span class="token plain"> name:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">;; reuse expression’s source location</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax/loc</span><span class="token plain"> expression</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-assign</span><span class="token plain"> name value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-get</span><span class="token plain"> obj:expr name:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax/loc</span><span class="token plain"> expression</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-set</span><span class="token plain"> obj name value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">parse-error</span><span class="token plain"> equal </span><span class="token string" style="color:#e3116c">"Invalid assignment target."</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">expression</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="lox">Lox<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#lox" class="hash-link" aria-label="Direct link to Lox" title="Direct link to Lox" translate="no">​</a></h2>
<p>The <code>lox.rkt</code> file takes the place of the interpreter from the book. Since this is a Racket language module, the goal is not to interpret Lox directly but to translate it into Racket. The expanded syntax is therefore responsible for reproducing the runtime errors that the interpreter would have raised.</p>
<p>The syntax produced by the parser is something like:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Sample expanded syntax</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-var-declaration</span><span class="token plain"> v </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-literal</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Hello World!"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-print</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-variable</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>We need to translate this to Racket standard forms and functions, with some attention because there are semantic differences between Racket and Lox that we need to handle on our own. For example Lox allows the following code (re-declaring a variable in a top-level scope)</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Lox variable re-definition</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">var v = "Hello World!";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var v = "a";</span><br></span></code></pre></div></div>
<p>Racket does not behave the same:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Racket variable re-definition</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> v </span><span class="token string" style="color:#e3116c">"Hello World!"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> v </span><span class="token string" style="color:#e3116c">"a"</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>It fails with</p>
<blockquote>
<p>module: identifier already defined in: v</p>
</blockquote>
<p>This is an essential difference but there are others as well, for example "truthiness" and the <code>nil</code> object, the lack of a <code>return</code> statement in Racket to be used inside of functions' bodies. I will go through some parts of the Lox expansion module to explain how it works.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="nil-and-truthiness">Nil and truthiness<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#nil-and-truthiness" class="hash-link" aria-label="Direct link to Nil and truthiness" title="Direct link to Nil and truthiness" translate="no">​</a></h3>
<p>Lox nil is represented by the <code>lox-nil</code> binding, whose value is the symbol <code>nil</code>. To support truthiness a helper function is defined and used to define other parts of the syntax interacting with boolean values.</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Truthiness</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-truthy?</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">not</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">or</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">eq?</span><span class="token plain"> v </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">eq?</span><span class="token plain"> v lox-nil</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-or</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">let </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">l-val</span><span class="token plain"> left</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-truthy?</span><span class="token plain"> l-val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> l-val right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-and</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">let </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">l-val</span><span class="token plain"> left</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-truthy?</span><span class="token plain"> l-val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> right l-val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-while</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> cond:expr body:expr ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">while </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-truthy?</span><span class="token plain"> cond</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> body ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-if</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> cond then</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">when </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-truthy?</span><span class="token plain"> cond</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         then</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> cond then else</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">if </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-truthy?</span><span class="token plain"> cond</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> then else</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-unary</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">line</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #:datum-literals </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">BANG</span><span class="token plain"> MINUS</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> BANG v:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">not </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-truthy?</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> MINUS v:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-negate-impl v line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="binary-operations">Binary operations<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#binary-operations" class="hash-link" aria-label="Direct link to Binary operations" title="Direct link to Binary operations" translate="no">​</a></h3>
<p>I already described the macro used during the parsing phase of the language module. Also during expansion, I used macros to remove some code duplication in addition to a function helper used to do arguments validation.</p>
<p>A rather big macro performs a "dispatch" to the function defining the binary operations. When possible numeric binary operations are defined using the helper <code>lox-number-binary-with-validation</code>, some others like <code>lox-add-impl</code> are defined ad hoc.</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Binary expression expansion</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-binary</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">line</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      #:datum-literals</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">PLUS</span><span class="token plain"> MINUS GREATER GREATER_EQUAL LESS LESS_EQUAL SLASH STAR BANG_EQUAL EQUAL_EQUAL AND OR</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr PLUS right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-add-impl left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr MINUS right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-number-binary-with-validation - left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr GREATER right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-number-binary-with-validation &gt; left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr GREATER_EQUAL right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-number-binary-with-validation &gt;= left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr LESS right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-number-binary-with-validation &lt; left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr LESS_EQUAL right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-number-binary-with-validation &lt;= left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr SLASH right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-divide-impl left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr STAR right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-number-binary-with-validation * left right line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr BANG_EQUAL right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">not </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-eqv?</span><span class="token plain"> left right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr EQUAL_EQUAL right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-eqv? left right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr AND right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-and left right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> left:expr OR right:expr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-or left right</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="undefined-variables">Undefined variables<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#undefined-variables" class="hash-link" aria-label="Direct link to Undefined variables" title="Direct link to Undefined variables" translate="no">​</a></h3>
<p>Lox undefined variable behavior, a runtime error with a specific error code and message, is implemented partially here and partially in the main module. In Racket <a href="https://docs.racket-lang.org/reference/syntax-model.html#%28part._expand-steps%29" target="_blank" rel="noopener noreferrer" class="">any unbound identifier is expanded through a #%top form</a> which I'm overriding to get the desired behavior. So I defined a <code>lox-top</code> macro:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-top</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> . id:id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">line</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">or</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">str-id</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">symbol-&gt;string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-&gt;datum</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-runtime-error </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">format</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Undefined variable '~a'."</span><span class="token plain"> str-id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>This macro is used in the main module to override the default <code>#%top</code> form.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="return-statement">Return statement<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#return-statement" class="hash-link" aria-label="Direct link to Return statement" title="Direct link to Return statement" translate="no">​</a></h3>
<p>Racket does not have a built-in return statement for function bodies, but it provides the machinery needed to implement one. The core runtime piece is let/ec, which gives us an escape continuation. The macro-level piece is a syntax parameter: while expanding a function body, I rename return-param to that function’s escape continuation. This means that each function body expands with its own target for lox-return, so returns inside nested functions correctly exit the inner function rather than the outer one.</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Simple early exit from function</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">let/ec</span><span class="token plain"> k</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"inside function"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">k</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"post early return"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">; sample execution</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> v </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">foo</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> v</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">; output</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">; inside function</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">; 1</span><br></span></code></pre></div></div>
<p>The documentation on <a href="https://docs.racket-lang.org/reference/cont.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._let%2Fec%29%29" target="_blank" rel="noopener noreferrer" class="">Racket docs for <code>let/ec</code> is pretty scarce</a> and I don't have much to add besides that the approach works and it is simple to use.</p>
<p>We can see that the <code>k</code> in <code>let/ec k</code> is a new binding that's being introduced because <code>(let/ec k body ...+)</code> is equivalent to <code>(call/ec (lambda (k) body ...))</code>. We would like to return whenever we encounter a <code>lox-return</code> either alone or with a following value/expression. Using <code>(let/ec lox-return ...)</code> wouldn't work because we are defining a new binding and not using our parsed syntax object.</p>
<p>That is why I use a syntax parameter together with <code>syntax-parameterize</code> and <code>make-rename-transformer</code>: inside that expansion context, <code>lox-return</code> is rewritten to the escape continuation <code>k</code>. Nested function bodies are expanded under their own parameterization, so a return always targets the correct function.</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Return statement implementation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">define-syntax-parameter</span><span class="token plain"> return-param</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token lambda-parameter">stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">raise-syntax-error</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"return used outside of function"</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-return</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">return-param val</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">; lox-run-callable-body is used multiple times</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">; otherwise it could have been included in the lox-function definition</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">define-syntax-rule</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-run-callable-body</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">param</span><span class="token plain"> binding</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> stmt ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">let/ec</span><span class="token plain"> k</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parameterize</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">return-param</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">make-rename-transformer</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'k</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                          </span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">param</span><span class="token plain"> binding</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-block</span><span class="token plain"> stmt ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-function</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> name:id </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">arg:id</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">stmt</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">define </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">name</span><span class="token plain"> arg ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-run-callable-body</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> stmt ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>The <code>lox-run-callable-body</code> indirection is useful to re-use the same code in function and in class methods. The <code>[param binding] ...</code> part is used in class methods to implement <code>this</code> and <code>super</code>, both are defined as <code>syntax-parameters</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="classes">Classes<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#classes" class="hash-link" aria-label="Direct link to Classes" title="Direct link to Classes" translate="no">​</a></h3>
<p>Class definition is by far the most complex part of the project. As just mentioned we need to support <code>this</code> and <code>super</code>, but also methods, fields, printing of class definition, class instance, instance methods etc. It's really a lot of functionality for a single language construct.</p>
<p>My first attempt at defining a Lox class used Racket’s class system, since it already supports fields, methods, <code>this</code>, and related features. Possibly not everything with the same semantics and functionality required by Lox but it was worth to give it a try.</p>
<p>I tried, however the expansion of a very simple class is extremely complex. The following racket code</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Racket empty class definition</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> foo% </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">class</span><span class="token plain"> object%</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>expands to</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Racket empty class expansion</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-values</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">foo%</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  compose-class</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token symbol" style="color:#36acaa">'foo%</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  object%</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"> list</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"> current-inspector</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token plain">#f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token plain">#f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token symbol" style="color:#36acaa">'0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token symbol" style="color:#36acaa">'normal</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token lambda-parameter">local-accessor local-mutator</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">letrec-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                       values</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"> list</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"> list</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"> list</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token lambda-parameter">self561</span><br></span><span class="token-line" style="color:#393A34"><span class="token lambda-parameter">                                super-go</span><br></span><span class="token-line" style="color:#393A34"><span class="token lambda-parameter">                                si_c</span><br></span><span class="token-line" style="color:#393A34"><span class="token lambda-parameter">                                si_inited?</span><br></span><span class="token-line" style="color:#393A34"><span class="token lambda-parameter">                                si_leftovers</span><br></span><span class="token-line" style="color:#393A34"><span class="token lambda-parameter">                                init-args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                         </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                           </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                             </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                               </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                 </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let-values</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                   </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">#%app</span><span class="token plain"> void</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                   </span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">declare-field-use-start</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token plain">#f</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">'</span><span class="token plain">#f</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>Troubleshooting my code scanner, parser and macros using this expansion for the class implementation was nearly impossible. I decided to follow an approach similar to the one used in the Crafting Interpreters book. I defined two types:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">struct</span><span class="token plain"> lox-class-constructor </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">base</span><span class="token plain"> name method-table superclass</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  #:property prop:procedure</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">struct-field-index</span><span class="token plain"> base</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">struct</span><span class="token plain"> lox-class-instance </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">class</span><span class="token plain"> fields</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>The first one, <code>lox-class-constructor</code>, is similar to <code>LoxClass</code> in Crafting Interpreters. The <code>#:property prop:procedure</code> makes the struct "callable", it is a procedure and, as the name suggests, an instance of <code>lox-class-constructor</code> once called will return an instance of the class it is defining. The <code>base</code> argument is the procedure that will be called when we call an instance of <code>lox-class-constructor</code>. The <code>lox-class-instance</code> is an instance of a given class.</p>
<p>Besides these custom types, the implementation needs several additional functions and macros. We want a <code>lox-class-constructor</code> to return a <code>lox-class-instance</code>. In practice, <code>lox-class-instance</code> is the runtime type representing an instance of a Lox class, and each instance must keep a reference to the <code>lox-class-constructor</code> that created it through its class field. Since these values refer to each other, their definitions are mutually recursive, so we use:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm" style="counter-reset:line-count 0"><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">make-lox-class-constructor</span><span class="token plain"> class-name-str superclass-value method-table</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">letrec</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">class</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-constructor</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                   </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> </span><span class="token lambda-parameter">ctor-args</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> fields </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">make-hash</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> self </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-instance</span><span class="token plain"> class fields</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> maybe-init </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-bind-method</span><span class="token plain"> class </span><span class="token symbol" style="color:#36acaa">'init</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">when</span><span class="token plain"> maybe-init</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-call-impl</span><span class="token plain"> maybe-init ctor-args </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">current-call-line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">when</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">and</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">not</span><span class="token plain"> maybe-init</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">not</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">null?</span><span class="token plain"> ctor-args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-runtime-error</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">format</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Expected 0 arguments but got ~a."</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                                                  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">length</span><span class="token plain"> ctor-args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                                          </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">current-call-line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                     self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                   class-name-str</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                   method-table</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                   superclass-value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    class</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span></span><br></span></code></pre></div></div>
<p>Let's go line by line:</p>
<ul>
<li class="">In line 1 we are defining a helper function <code>make-lox-class-constructor</code> that helps us build a <code>lox-class-constructor</code> instance for a given class.</li>
<li class="">In line 2 to define <code>lox-class-constructor</code> we need to define a function that returns a <code>lox-class-instance</code> holding a reference to the <code>lox-class-constructor</code>. We use letrec to allow using class inside its own definition.</li>
<li class="">In line 3 not much to say, syntax to define the lambda</li>
<li class="">In line 4 initiating a hash table to hold the fields of the instance</li>
<li class="">In line 5 defining the instance. Notice the <code>class</code> value passed into the struct constructor.</li>
<li class="">In line 6 looking for a <code>init</code> method using our helper <code>lox-class-bind-method</code></li>
<li class="">In lines 7-8 if there is a <code>init</code> method, we call it (line 8)</li>
<li class="">In lines 9-12 if there is no <code>init</code> but we got parameters we raise an error</li>
<li class="">In line 13 we use <code>self</code> as return value for the lambda we are defining and the lambda definition is done and so we have the first parameter for the <code>lox-class-constructor</code></li>
<li class="">In lines 14-16 we pass the remaining parameters</li>
<li class="">In line 17 we use <code>class</code> as return value for the <code>make-lox-class-constructor</code> we are defining.</li>
</ul>
<p>So we have now a helper function that helps us create a class constructor but what are the <code>superclass-value</code> and the <code>method-table</code>? Let's look at the actual <code>lox-class</code> syntax object and its expansion:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">lox-class expansion</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    #:datum-literals </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-function</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> class-name:id superclass:expr </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-function</span><span class="token plain"> m-name:id </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">m-arg:id</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">m-body:expr</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">class-line</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">or</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'class-name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">define class-name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">           </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">superclass-value</span><span class="token plain"> superclass</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">             </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-validate-superclass</span><span class="token plain"> superclass-value class-line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">             </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> method-table</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">make-hasheq</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">list</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-make-method-entry</span><span class="token plain"> m-name superclass-value </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">m-arg</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> m-body ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">             </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">make-lox-class-constructor</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">symbol-&gt;string</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'class-name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                         superclass-value</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                         method-table</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>First we notice that the <code>lox-class</code> expands to a <code>(define class-name ...)</code> binding <code>class-name</code> to the constructor of the class. The <code>superclass-value</code>, when available, will be the constructor of the super class. The method table is built some helper functions and macros.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="keywords-this-and-super-and-instance-methods-definition">Keywords <code>this</code> and <code>super</code> and instance methods definition<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#keywords-this-and-super-and-instance-methods-definition" class="hash-link" aria-label="Direct link to keywords-this-and-super-and-instance-methods-definition" title="Direct link to keywords-this-and-super-and-instance-methods-definition" translate="no">​</a></h3>
<p>In our lox class the methods are stored as factories in a method table in the class definition and not in the instance. The first helper we encounter to support this implementation is <code>lox-make-method-entry</code> which is a macro returning a pair of values: the method name and a method factory. The method factory is doing a lot of work:</p>
<ul>
<li class="">it uses <code>procedure-rename</code> so that when we print a method we get the desired name.</li>
<li class="">it binds <code>this</code> to <code>receiver</code>, the <code>this</code> value is bound at runtime that's why we need to pass it to the method so that it points to the correct instance of the class.</li>
<li class="">it binds <code>super</code> to <code>superclass-value</code>, the superclass is defined at compile time and indeed it is an argument of the macro itself.</li>
<li class="">it defines the body of the method: <code>result</code> is set to be the value returned by <code>lox-run-callable-body</code>.</li>
<li class="">it passes two new syntax parameter bindings so that <code>lox-this</code> and <code>lox-super</code> are correctly rewritten in the method body.</li>
<li class="">force the return of <code>this</code> if the method is <code>init</code></li>
</ul>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">lox method table helpers</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">define-syntax-rule</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-make-method-entry</span><span class="token plain"> m-name superclass-value </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">m-arg</span><span class="token plain"> ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> m-body ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">cons</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'m-name</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token lambda-parameter">receiver</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">procedure-rename</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">           </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token lambda-parameter">m-arg ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">             </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">this</span><span class="token plain"> receiver</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">super</span><span class="token plain"> superclass-value</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> result</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                 </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-run-callable-body</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">this-param</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">make-rename-transformer</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                         </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">super-param</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">make-rename-transformer</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'super</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                        m-body ...</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">eq?</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'m-name</span><span class="token plain"> </span><span class="token symbol" style="color:#36acaa">'init</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> this result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">           </span><span class="token symbol" style="color:#36acaa">'m-name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="instance-method-executions">Instance method executions<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#instance-method-executions" class="hash-link" aria-label="Direct link to Instance method executions" title="Direct link to Instance method executions" translate="no">​</a></h3>
<p>Calling a method on an instance is another complex part of the implementation. Let's start with a simple class definition with an empty method:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Lox class with one empty method</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">class A {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  method() {}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var a = A();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">a.method();</span><br></span></code></pre></div></div>
<p>Let's look at the expansion of this simple code:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Lox class with one empty method expansion</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class</span><span class="token plain"> A </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-function</span><span class="token plain"> method </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-var-declaration</span><span class="token plain"> a </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-call</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-variable</span><span class="token plain"> A</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-call</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-get</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-variable</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"method"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>We are interested in the last line where we have an interaction between <code>lox-call</code> and <code>lox-get</code>. I said already that the instances in racket-lox hold a method factory table and we need to pass the receiver at runtime to get the actual function to be called. All of this is done by the <code>lox-get</code> macro and the more interesting <code>lox-get-impl</code> function:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">lox-get definition</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-get</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> obj method:str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">method-sym</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">string-&gt;symbol</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-&gt;datum</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'method</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">line</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">or</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'method</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-get-impl obj </span><span class="token symbol" style="color:#36acaa">'method-sym</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-get-impl</span><span class="token plain"> o symbol-name line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">cond</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-instance?</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">hash-ref</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-instance-fields</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               symbol-name</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">lambda</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                 </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> maybe-method</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                   </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-bind-method</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-instance-class</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> symbol-name o</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                 </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> maybe-method</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                     maybe-method</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-runtime-error</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">format</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Undefined property '~a'."</span><span class="token plain"> symbol-name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-runtime-error</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Only instances have properties."</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>The macro is only extracting the original line in the source code and the method name and passing both to the function along with the instance of the class. The function checks if the instance contains a field with that <code>symbol-name</code> name and returns it if that's the case. Otherwise it tries to bind the method to the current instance of the class. The <code>lox-class-bind-method</code> receives the class <code>(lox-class-instance-class o)</code> as holder of the method factory table, the method name <code>symbol-name</code> and the instance <code>o</code> to be able to bind the method to the correct receiver. In order to work properly <code>lox-class-bind-method</code> needs to look recursively up to the inheritance tree to look for the method whenever it doesn't find it on the current class.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="property-lookup">Property lookup<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#property-lookup" class="hash-link" aria-label="Direct link to Property lookup" title="Direct link to Property lookup" translate="no">​</a></h3>
<p>There is not much to add here. We already discussed how <code>lox-get-impl</code> searches for the symbol it receives inside the hashmap of the instance fields.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="super">Super<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#super" class="hash-link" aria-label="Direct link to Super" title="Direct link to Super" translate="no">​</a></h3>
<p>With all we have seen so far, <code>super</code> implementation is pretty straightforward. Let's start with the expansion:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Two lox classes with inheritance and super usage</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">class A {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  methodA()  {print "inside A";}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">class B &lt; A {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  method() { super.methodA();}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">super expansion</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class</span><span class="token plain"> A </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-function</span><span class="token plain"> methodA </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class</span><span class="token plain"> B A </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-function</span><span class="token plain"> method </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-call</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-super</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"methodA"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>The implementation is made of a macro and a function:</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">lox-super implementation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-super</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-parse</span><span class="token plain"> stx</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">_</span><span class="token plain"> method:str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">with-syntax</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">method-sym</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">string-&gt;symbol</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-&gt;datum</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'method</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">line</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">or</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> #</span><span class="token symbol" style="color:#36acaa">'method</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">syntax-line</span><span class="token plain"> stx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       #</span><span class="token punctuation" style="color:#393A34">'</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lox-super-impl super-param this-param </span><span class="token symbol" style="color:#36acaa">'method-sym</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-super-impl</span><span class="token plain"> superclass receiver method-sym line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-constructor?</span><span class="token plain"> superclass</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">method</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-bind-method</span><span class="token plain"> superclass method-sym receiver</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> method</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            method</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-runtime-error</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">format</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Undefined property '~a'."</span><span class="token plain"> method-sym</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-runtime-error</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Superclass must be a class."</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>The macro (again) is not doing much, it extracts the line number and method name and passes them to the <code>lox-super-impl</code> along with the <code>this</code> and <code>super</code> syntax parameters. The function <code>lox-super-impl</code> is passing the values to <code>lox-class-bind-method</code>, which we already discussed, starting the recursive lookup from the parent class instead of the current class like it is done in the method lookup flow.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="additional-compatibility-gaps-between-lox-and-racket">Additional compatibility gaps between Lox and Racket<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#additional-compatibility-gaps-between-lox-and-racket" class="hash-link" aria-label="Direct link to Additional compatibility gaps between Lox and Racket" title="Direct link to Additional compatibility gaps between Lox and Racket" translate="no">​</a></h3>
<p>Racket semantics differs from Lox semantics on a few additional points:</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="printing">Printing<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#printing" class="hash-link" aria-label="Direct link to Printing" title="Direct link to Printing" translate="no">​</a></h4>
<p>The <code>lox-print</code> implementation feels a bit "hacky" however it works correctly. A bunch of runtime checks allow to tailor the printed string to the Lox requirements. The <code>lox-class-constructor</code> and <code>lox-class-instance</code> custom structs help with the printing as well. Native types, such as booleans and numbers have their own helpers to support Lox-style printing.</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">lox-print implementation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-print</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">cond</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">boolean?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">print-bool</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">eqv?</span><span class="token plain"> value </span><span class="token symbol" style="color:#36acaa">'nil</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"nil"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">number?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-number-&gt;string</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-constructor?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-constructor-name</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-instance?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">format</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"~a instance"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-constructor-name</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-class-instance-class</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">procedure?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token function" style="color:#d73a49">function-name</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">object-name</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">eqv?</span><span class="token plain"> function-name </span><span class="token symbol" style="color:#36acaa">'clock</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">           </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;native fn&gt;"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">           </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">format</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;fn ~a&gt;"</span><span class="token plain"> function-name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">displayln</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-number-&gt;string</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">cond</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">;; Preserve negative zero so `print -0;` matches Crafting Interpreters output.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">and</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">real?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">inexact?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">eqv?</span><span class="token plain"> value </span><span class="token number" style="color:#36acaa">-0.0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"-0"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">;; Lox prints whole-valued numbers without a trailing ".0".</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">and</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">real?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">integer?</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">number-&gt;string</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">inexact-&gt;exact</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">number-&gt;string</span><span class="token plain"> value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="numbers">Numbers<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#numbers" class="hash-link" aria-label="Direct link to Numbers" title="Direct link to Numbers" translate="no">​</a></h4>
<p>There are a few differences between how Racket handles and prints numbers and how Lox does it. The previous section showcases the snippet that handles printing of <code>-0.0</code> and printing of <code>1.0</code> as <code>1</code>. Division in Lox is implemented using Java double division. Similarly we are using inexact numbers. Number equality requires some extra handling for numbers as well.</p>
<div class="language-scheme codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Division implementation in racket-lox</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-scheme codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-divide-impl</span><span class="token plain"> av bv line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">and</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">number?</span><span class="token plain"> av</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">number?</span><span class="token plain"> bv</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">exact-&gt;inexact</span><span class="token plain"> av</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">exact-&gt;inexact</span><span class="token plain"> bv</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-runtime-error</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Operands must be numbers."</span><span class="token plain"> line</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">define</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">lox-eqv?</span><span class="token plain"> a b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">cond</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">and</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">real?</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">nan?</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">and</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">real?</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">nan?</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">#f</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">and</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">number?</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">number?</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> a b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">eqv?</span><span class="token plain"> a b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-clock-function">The clock function<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#the-clock-function" class="hash-link" aria-label="Direct link to The clock function" title="Direct link to The clock function" translate="no">​</a></h4>
<p>The <code>clock</code> function is defined and exported in the <code>main.rkt</code> file. That makes it available to racket-lox programs.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="drracket-not-supported-properly">DrRacket not supported properly<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#drracket-not-supported-properly" class="hash-link" aria-label="Direct link to DrRacket not supported properly" title="Direct link to DrRacket not supported properly" translate="no">​</a></h4>
<p>In order to implement Lox exit codes on failure, racket-lox has dedicated errors and errors handlers and doesn't raise syntax errors that would make syntax error highlighting work with DrRacket. The colorer, fully AI generated, gives racket-lox a decent aspect in DrRacket without being perfect. Indentation is wrong for example. I didn't invest much time in this I just wanted code and comments to be colored correctly.</p>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorTargetStickyNavbar_Vzrq sr-only" id="footnote-label">Footnotes<a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes" translate="no">​</a></h2>
<ol>
<li class="anchorTargetStickyNavbar_Vzrq" id="user-content-fn-1-36a7e0">
<p>More details on syntax coloring <a href="https://docs.racket-lang.org/tools/lang-languages-customization.html#%28idx._%28gentag._0._%28lib._scribblings%2Ftools%2Ftools..scrbl%29%29%29" target="_blank" rel="noopener noreferrer" class="">here</a> <a href="https://davidelettieri.it/2026/04/06/lox-as-a-racket-language-module#user-content-fnref-1-36a7e0" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category>lox</category>
            <category>racket</category>
        </item>
        <item>
            <title><![CDATA[Extensible Visitor Pattern in C#]]></title>
            <link>https://davidelettieri.it/2025/11/26/extensible-visitor-pattern</link>
            <guid>https://davidelettieri.it/2025/11/26/extensible-visitor-pattern</guid>
            <pubDate>Sat, 15 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Recently, I stumbled upon this paper Synthesizing Object-Oriented and Functional Design to Promote Re-Use. The paper wants to provide a solution to the expression problem. The authors suggest an improved version of the visitor pattern that they call "extensible visitor pattern" which is essentially a combination of the visitor pattern with the factory method pattern.]]></description>
            <content:encoded><![CDATA[<p>Recently, I stumbled upon this paper <a href="https://cs.brown.edu/~sk/Publications/Papers/Published/kff-synth-fp-oo/" target="_blank" rel="noopener noreferrer" class="">Synthesizing Object-Oriented and Functional Design to Promote Re-Use</a>. The paper wants to provide a solution to the <a href="https://web.archive.org/web/20250907153845/https://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt" target="_blank" rel="noopener noreferrer" class="">expression problem</a>. The authors suggest an improved version of the visitor pattern that they call "extensible visitor pattern" which is essentially a combination of the <a href="https://refactoring.guru/design-patterns/visitor" target="_blank" rel="noopener noreferrer" class="">visitor pattern</a> with the <a href="https://refactoring.guru/design-patterns/factory-method" target="_blank" rel="noopener noreferrer" class="">factory method</a> pattern.</p>
<p>While the paper and the expression problem statement don't explicitly mention SOLID principles, it looks like what they are really doing is exploring how to evolve a code base while respecting the <strong>Open/Closed Principle</strong>:</p>
<blockquote>
<p>Software entities (like classes, methods, and functions) should be open for extension, but closed for modification.</p>
</blockquote>
<p>The idea that software entities should be open for extension is intuitive, we can add new code, inherit types, compose etc. But what does it mean closed for modification? Should we never change code that has been deployed to production? Is that what the principle is saying?</p>
<p>In my opinion, changing a piece of code for fixing a bug doesn't go against this principle, I believe that the principle suggests that we should be able to not change existing code when we want to add some functionality.</p>
<p>Honestly, if I think about this principle and what I saw in my career in software development, I can safely affirm that I never saw this principle applied faithfully. Classes, methods and all software constructs are modified <em>all the time</em>.</p>
<p>The authors work through several examples all based on the same scenario: we have a set of shapes and a set of tools, essentially functions, over these shapes and we want either to add a new shape or to add a new tool. How can we update our code without changing the existing code? And what impact does our approach have on clients using our code?</p>
<p>They present 4 different implementations:</p>
<ul>
<li class="">functional without any pattern</li>
<li class="">object oriented using the interpreter pattern</li>
<li class="">object oriented using the visitor pattern</li>
<li class="">object oriented using the extensible visitor pattern that is subject of the paper</li>
</ul>
<p>The code samples are written in Java, a language called "Pizza" which is "a parametrically polymorphic extension of Java", and <code>SML</code> for the functional approach example. Given that I'm a big fan of the visitor pattern, I wanted to go through the paper and reimplement everything using F# for the functional approach and C# for everything else. The code will not be an exact port of the original, mostly because I don't know Pizza nor Java but also because they don't show all the code and I want to show a bit more than they did.</p>
<p>The key point to observe in the presented problem is that the <em>types are recursive</em>, in other words shapes are defined using other shapes. For example the translation of a shape, or a union of two shapes. This case cannot be ignored when we build a tree of types to represent some kind of domain and problem.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>The authors used an abstract class as base type for the object oriented approaches, I used an interface. I'll try to motivate my choice later on.</p></div></div>
<p>All the code is available here <a href="https://github.com/davidelettieri/extensible-visitor" target="_blank" rel="noopener noreferrer" class="">https://github.com/davidelettieri/extensible-visitor</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="functional-approach">Functional approach<a href="https://davidelettieri.it/2025/11/26/extensible-visitor-pattern#functional-approach" class="hash-link" aria-label="Direct link to Functional approach" title="Direct link to Functional approach" translate="no">​</a></h2>
<p>The functional approach is the simplest and shortest of all, it is super easy to add a new tool and it is impossible to add new datatype without changing existing code. Let's examine why it's impossible.</p>
<div class="language-fsharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Functional approach - F# implementation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-fsharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Point</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> X</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">float</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> Y</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">float</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token class-name">Shape</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> Circle </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> radius</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">float</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> Square </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> length</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">float</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> Translated </span><span class="token keyword" style="color:#00009f">of</span><span class="token plain"> shape</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Shape</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> offset</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Point</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">rec</span><span class="token plain"> containsPoint shape point </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">match</span><span class="token plain"> shape </span><span class="token keyword" style="color:#00009f">with</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> Circle radius </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> radius </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> radius</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> Square length </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> length </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> length</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Translated</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">shape</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> offset</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> translatedPoint </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> X </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> offset</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              Y </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> offset</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        containsPoint shape translatedPoint</span><br></span></code></pre></div></div>
<p>If we want to add a shape we need to modify the <code>Shape</code> definition, there is no way around that.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>To be honest, I'm not sure this is totally bad. The code is so short and clean and adding a new type will trigger a compilation error. It's exactly what we want, we know where we have to fix the code so that the new shape is supported everywhere. But doubting the <strong>OCP</strong> is beyond the scope of this post.</p></div></div>
<p>As a bonus I tried a functional approach in C# and while the result is more verbose, we are able to define a new function <code>ContainsPointV2()</code> that supports a new shape and we don't need to modify any existing code.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Functional approach - C# Pattern Matching</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Tools</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">IShape</span><span class="token plain"> shape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        shape </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token return-type class-name">Square</span><span class="token plain"> s </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token return-type class-name">Circle</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Radius </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Radius</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token return-type class-name">TranslatedShape</span><span class="token plain"> ts </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            _ </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">NotSupportedException</span><span class="token punctuation" style="color:#393A34">(</span><span class="token interpolation-string string" style="color:#e3116c">$"Shape of type </span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">{</span><span class="token interpolation-string interpolation expression language-csharp">shape</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">.</span><span class="token interpolation-string interpolation expression language-csharp function" style="color:#d73a49">GetType</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">(</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">)</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">.</span><span class="token interpolation-string interpolation expression language-csharp">Name</span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">}</span><span class="token interpolation-string string" style="color:#e3116c"> is not supported"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// sorry for the bad naming</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPointV2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">IShape</span><span class="token plain"> shape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        shape </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token return-type class-name">Square</span><span class="token plain"> s </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token return-type class-name">Circle</span><span class="token plain"> c </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">            </span><span class="token return-type class-name">TranslatedShape</span><span class="token plain"> ts </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPointV2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                ts</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token return-type class-name">UnionShape</span><span class="token plain"> s </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPointV2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPointV2</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> s</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            _ </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">NotSupportedException</span><span class="token punctuation" style="color:#393A34">(</span><span class="token interpolation-string string" style="color:#e3116c">$"Shape of type </span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">{</span><span class="token interpolation-string interpolation expression language-csharp">shape</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">.</span><span class="token interpolation-string interpolation expression language-csharp function" style="color:#d73a49">GetType</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">(</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">)</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">.</span><span class="token interpolation-string interpolation expression language-csharp">Name</span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">}</span><span class="token interpolation-string string" style="color:#e3116c"> is not supported"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The highlighted line is key in correctly supporting the new shape. Since the <code>TranslatedShape</code> type is recursive, when we define a new tool to support a new shape, any instance of <code>TranslatedShape</code> could contain an instance of the <code>UnionShape</code>. This means that the recursive call needs to be done using the new tool definition. In this case <code>ContainsPointV2()</code>. This recursion is <strong>the key</strong> for understanding the approach of the paper and the extensible visitor pattern implements this exact behavior.</p>
<p>Of course with this approach we are accepting the fact that we might get runtime exceptions, for example if someone passes a <code>UnionShape</code> instance to <code>ContainsPoint()</code>. Not exactly safe and while we are not changing our code, clients using our code need to update to <code>ContainsPointV2()</code> in order to be able to handle correctly the new <code>UnionShape</code> type.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="object-oriented-with-the-interpreter-pattern">Object oriented with the interpreter pattern<a href="https://davidelettieri.it/2025/11/26/extensible-visitor-pattern#object-oriented-with-the-interpreter-pattern" class="hash-link" aria-label="Direct link to Object oriented with the interpreter pattern" title="Direct link to Object oriented with the interpreter pattern" translate="no">​</a></h2>
<p>Using the interpreter pattern means that each tool is a function on the data type, this pattern is usually explained with grammars or expressions however it has a more generic applicability. Whenever we have a family of types which expose the same behavior, a method, then we have a usage of the interpreter pattern.</p>
<p>The approach that is proposed is the following:</p>
<ol>
<li class="">we start with a set of types all extending a base abstract class with a method representing the initial tool supported by the types.</li>
<li class="">we want to add a new shape. We define a new type that inherits the base abstract class and implement the method.</li>
<li class="">we want to add a new tool. We cannot add a new method to the existing types because we don't want to modify existing code. Instead, we define new types that extend the original one implementing the new tool.</li>
</ol>
<p>Unfortunately existing clients of our code need to change the types they are using in order to leverage the new tool.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="remarks-on-the-interpreter-pattern-and-the-provided-implementation">Remarks on the interpreter pattern and the provided implementation<a href="https://davidelettieri.it/2025/11/26/extensible-visitor-pattern#remarks-on-the-interpreter-pattern-and-the-provided-implementation" class="hash-link" aria-label="Direct link to Remarks on the interpreter pattern and the provided implementation" title="Direct link to Remarks on the interpreter pattern and the provided implementation" translate="no">​</a></h3>
<p>In the original GoF definition and in the code samples provided by the authors in the article the base type is an abstract class but there are some unclear points:</p>
<ul>
<li class="">the base abstract class is having the <code>shrink</code> method but all the initial shapes implement <code>containsPt</code>, the authors probably wanted the base abstract class to have the <code>containsPt</code> method</li>
<li class="">the new union shape implements <code>containsPt</code></li>
<li class="">the newly implemented types extending the original shapes to have the <code>shrink</code> method don't have a base type in common which is a requirement to be able to handle shapes in a polymorphic manner.</li>
</ul>
<p>The last point is why I decided to use interfaces for the C# code, imagine we define a new base abstract class for the shrinkable shapes. Then in order to allow code reuse we would have to inherit from multiple base types for example:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Interpreter Pattern - Abstract class based inheritance problem</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">abstract</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Shape</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token range operator" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">abstract</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ShrinkableShape</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token range operator" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Square</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">Shape</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token range operator" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ShrinkableSquare</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">Square</span><span class="token type-list punctuation" style="color:#393A34">,</span><span class="token type-list"> </span><span class="token type-list class-name">ShrinkableShape</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Impossible!</span><br></span></code></pre></div></div>
<p>As noted in the code listing and as probably every reader knows we cannot inherit multiple classes, however we can implement multiple interfaces.</p>
<figure><img style="margin:0 auto;display:block" alt="Fig 4-5-6 from Synthesizing Object-Oriented and Functional Design to Promote Re-Use" src="https://davidelettieri.it/img/Synthesizing%20Object-Oriented%20and%20Functional%20Design%20to%20Promote%20Re-Use%20fig4-5-6.png"><figcaption>Fig 4,5,6 from the article with some comments</figcaption></figure>
<p>So, omitting most of the code, a shrinkable shape using the interpreter pattern in C# with interfaces instead of abstract base classes would look like this:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Interpreter Pattern - Shrinkable Shape Implementation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">IShrinkableShape</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">IShape</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token return-type class-name">IShrinkableShape</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Shrink</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">record</span><span class="token plain"> </span><span class="token class-name">ShrinkableSquare</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> Length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">Square</span><span class="token type-list record-arguments punctuation" style="color:#393A34">(</span><span class="token type-list record-arguments">Length</span><span class="token type-list record-arguments punctuation" style="color:#393A34">)</span><span class="token type-list punctuation" style="color:#393A34">,</span><span class="token type-list"> </span><span class="token type-list class-name">IShrinkableShape</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">IShrinkableShape</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Shrink</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">ShrinkableSquare</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Length </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="object-oriented-with-the-visitor-pattern">Object oriented with the visitor pattern<a href="https://davidelettieri.it/2025/11/26/extensible-visitor-pattern#object-oriented-with-the-visitor-pattern" class="hash-link" aria-label="Direct link to Object oriented with the visitor pattern" title="Direct link to Object oriented with the visitor pattern" translate="no">​</a></h2>
<p>The visitor pattern is very much the same approach as the functional one. Adding a tool is the easy part because it only entails defining a new visitor type. The following is how we would approach in C#.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Visitor Pattern - Core Implementation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">IShape</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token return-type class-name">T</span><span class="token plain"> </span><span class="token generic-method function" style="color:#d73a49">Process</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&lt;</span><span class="token generic-method generic class-name">T</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">IShapeProcessor</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"> processor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">IShapeProcessor</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token return-type class-name">T</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForSquare</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Square</span><span class="token plain"> square</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token return-type class-name">T</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForCircle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Circle</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token return-type class-name">T</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForTranslatedShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TranslatedShape</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">sealed</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">record</span><span class="token plain"> </span><span class="token class-name">Square</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> Length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">IShape</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">T</span><span class="token plain"> </span><span class="token generic-method function" style="color:#d73a49">Process</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&lt;</span><span class="token generic-method generic class-name">T</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">IShapeProcessor</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"> processor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> processor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ForSquare</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// more shapes</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> IShapeProcessor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">bool</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForSquare</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Square</span><span class="token plain"> square</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> square</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> square</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForCircle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Circle</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Radius </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Radius</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForTranslatedShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TranslatedShape</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">sealed</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Shrink</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> num</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> IShapeProcessor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">IShape</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// omitted</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Adding a new shape without modifying existing code is more challenging. As for the interpreter pattern we proceed by adding new code: the new shape type, a new visitor interface that inherits from the existing one and is able to process also the new shape and, lastly, the implementation of our tools.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Visitor Pattern - Adding Union Shape Support</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">IUnionShapeProcessor</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">IShapeProcessor</span><span class="token type-list class-name punctuation" style="color:#393A34">&lt;</span><span class="token type-list class-name">T</span><span class="token type-list class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token return-type class-name">T</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForUnionShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">UnionShape</span><span class="token plain"> unionShape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">sealed</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">record</span><span class="token plain"> </span><span class="token class-name">UnionShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">IShape</span><span class="token plain"> Shape1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">IShape</span><span class="token plain"> Shape2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">IShape</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">T</span><span class="token plain"> </span><span class="token generic-method function" style="color:#d73a49">Process</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&lt;</span><span class="token generic-method generic class-name">T</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">IShapeProcessor</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"> processor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">processor </span><span class="token keyword" style="color:#00009f">is</span><span class="token plain"> </span><span class="token class-name">IUnionShapeProcessor</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name">T</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"> unionProcessor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> unionProcessor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ForUnionShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">NotSupportedException</span><span class="token punctuation" style="color:#393A34">(</span><span class="token interpolation-string string" style="color:#e3116c">$"Processor of type </span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">{</span><span class="token interpolation-string interpolation expression language-csharp">processor</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">.</span><span class="token interpolation-string interpolation expression language-csharp function" style="color:#d73a49">GetType</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">(</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">)</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">.</span><span class="token interpolation-string interpolation expression language-csharp">Name</span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">}</span><span class="token interpolation-string string" style="color:#e3116c"> does not support UnionShape"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UnionContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> IUnionShapeProcessor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">bool</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForUnionShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">UnionShape</span><span class="token plain"> unionShape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        unionShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> unionShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The obvious difference is that our original implementation is type safe while the new one is relying on runtime checks to validate that the visitor instance is able to handle the new shape. However, as the authors point out, there is a less obvious, critical flaw: this implementation does not work for recursive types. The issue is with the recursive type <code>TranslatedShape</code>, the <code>UnionContainsPoint</code> visitor is reusing the base implementation of <code>ContainsPoint</code>. This means that it is executing the following code</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Visitor Pattern - Recursive Type Limitation</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForTranslatedShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TranslatedShape</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>Which is calling <code>Process</code> on the inner shape of the original object and it is passing a new instance of <code>ContainsPoint</code> (and not <code>UnionContainsPoint</code>!) so now we lost support for the <code>Union</code> shape. A unit test can confirm the expected behavior:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Visitor Pattern - Test for Nested Translated Shape</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">[</span><span class="token attribute class-name">Fact</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">TestNestedTranslatedShapes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Arrange</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> circle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Circle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> square </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Square</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> t1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">UnionShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">square</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> t2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">TranslatedShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Act &amp; Assert</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Assert</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-method function" style="color:#d73a49">Throws</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&lt;</span><span class="token generic-method generic class-name">NotSupportedException</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> t2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">UnionContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The power of the visitor pattern comes from the fact that with a single call <code>t2.Process(...)</code> we are calling 2 methods on 2 different object obtaining a double dispatch at runtime. However when the <code>ContainsPoint</code> visitor is creating an instance of itself and that behavior is inherited by new visitor types, we are breaking the double dispatch because <code>ForTranslatedShape</code> will pass to <code>Process</code> the original visitor instance and not the extended one.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="object-oriented-with-the-extensible-visitor-pattern">Object oriented with the extensible visitor pattern<a href="https://davidelettieri.it/2025/11/26/extensible-visitor-pattern#object-oriented-with-the-extensible-visitor-pattern" class="hash-link" aria-label="Direct link to Object oriented with the extensible visitor pattern" title="Direct link to Object oriented with the extensible visitor pattern" translate="no">​</a></h2>
<p>The key part to understand from the visitor pattern approach is that a tool implementation, a visitor, will break if its implementation is creating new instances of itself or other tools. Today, at least in C# world, we are quite used to not directly create instances of types and relying on dependency injection to get our instances and to plug-in different instances when needed.</p>
<p>A visitor directly creating an instance of its same type or another is clearly coupling itself to some specific implementation. The solution is to abstract the creation away so that we can use different instances, with the same interfaces, if we need to update a visitor to handle a new type. The following code shows how to implement it using a virtual method on the processor.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Visitor with virtual method to create instances of itself</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> IShapeProcessor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">bool</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">protected</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> </span><span class="token return-type class-name">ContainsPoint</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">MakeContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForSquare</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Square</span><span class="token plain"> square</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> square</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> square</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForCircle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Circle</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Radius </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> circle</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Radius</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForTranslatedShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TranslatedShape</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">MakeContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">X</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> translatedShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Point</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UnionContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">point</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> IUnionShapeProcessor</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">bool</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">protected</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">override</span><span class="token plain"> </span><span class="token return-type class-name">ContainsPoint</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">MakeContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Point</span><span class="token plain"> p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">UnionContainsPoint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ForUnionShape</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">UnionShape</span><span class="token plain"> unionShape</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        unionShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> unionShape</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Shape2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The <code>UnionContainsPoint</code> type, by overriding the <code>MakeContainsPoint</code> virtual method is able to update the behavior of the base class to recognize the new shape. This is very much similar to the function <code>ContainsPointV2</code> that is recursively calling itself.</p>]]></content:encoded>
            <category>c#</category>
            <category>visitor-pattern</category>
            <category>design-patterns</category>
        </item>
        <item>
            <title><![CDATA[Sutton & Barto Gridworld example in C#]]></title>
            <link>https://davidelettieri.it/2025/10/19/sutton-barto-gridworld</link>
            <guid>https://davidelettieri.it/2025/10/19/sutton-barto-gridworld</guid>
            <pubDate>Sun, 19 Oct 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Lately, I've been exploring various examples from Sutton and Barto's "Reinforcement Learning]]></description>
            <content:encoded><![CDATA[<p>Lately, I've been exploring various examples from Sutton and Barto's "Reinforcement Learning: An Introduction" book using C# and I already shared a few of them on this blog:</p>
<ul>
<li class=""><a class="" href="https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp">Tic-tac-toe reinforcement learning with C#</a></li>
<li class=""><a class="" href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp">Ten armed testbed for the Bandit problem with C#</a></li>
<li class=""><a class="" href="https://davidelettieri.it/2025/05/01/multi-armed-bandit-ex-2.5-csharp">Multi-armed bandit exercise 2.5 with C#</a></li>
</ul>
<p>Today I'll be focusing on the gridworld example from chapter 3 of the book. <a href="https://github.com/davidelettieri/sutton-barto-reinforcement-learning/tree/main/gridworld" target="_blank" rel="noopener noreferrer" class="">The code is available in the existing repo as a new project</a>. Gridworld is a simple example used to illustrate the Bellman equations and iterative policy evaluation. An excerpt from the book describes the environment:</p>
<blockquote>
<p>The cells of the grid correspond to the states of the environment. At
each cell, four actions are possible: north, south, east, and west, which deterministically
cause the agent to move one cell in the respective direction on the grid. Actions that
would take the agent off the grid leave its location unchanged, but also result in a reward
of -1. Other actions result in a reward of 0, except those that move the agent out of the
special states A and B. From state A, all four actions yield a reward of +10 and take the
agent to A'. From state B, all actions yield a reward of +5 and take the agent to B'.</p>
<p>— Sutton &amp; Barto, Reinforcement Learning: An Introduction, 2nd ed., Chapter 3.</p>
</blockquote>
<p>The value function for each state is updated using the Bellman expectation equation for policy evaluation:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mi>π</mi></msub><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><munder><mo>∑</mo><mi>a</mi></munder><mi>π</mi><mo stretchy="false">(</mo><mi>a</mi><mi mathvariant="normal">∣</mi><mi>s</mi><mo stretchy="false">)</mo><munder><mo>∑</mo><mrow><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo separator="true">,</mo><mi>r</mi></mrow></munder><mi>p</mi><mo stretchy="false">(</mo><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo separator="true">,</mo><mi>r</mi><mi mathvariant="normal">∣</mi><mi>s</mi><mo separator="true">,</mo><mi>a</mi><mo stretchy="false">)</mo><mo stretchy="false">[</mo><mi>r</mi><mo>+</mo><mi>γ</mi><msub><mi>v</mi><mi>π</mi></msub><mo stretchy="false">(</mo><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">)</mo><mo stretchy="false">]</mo><mo separator="true">,</mo><mspace width="1em"></mspace><mi mathvariant="normal">∀</mi><mi>s</mi><mo>∈</mo><mi>S</mi></mrow><annotation encoding="application/x-tex">v_{\pi}(s) = \sum_{a} \pi(a|s) \sum_{s',r} p(s',r|s,a) [r + \gamma v_{\pi}(s')], \quad \forall s \in S</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em">π</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.4801em;vertical-align:-1.4301em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.25em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.03588em">π</span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mord">∣</span><span class="mord mathnormal">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.856em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6828em"><span style="top:-2.786em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight" style="margin-right:0.02778em">r</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4301em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">p</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8019em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.02778em">r</span><span class="mord">∣</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">a</span><span class="mclose">)</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.02778em">r</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.0519em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.05556em">γ</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em">π</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8019em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mclose">)]</span><span class="mpunct">,</span><span class="mspace" style="margin-right:1em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord">∀</span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.05764em">S</span></span></span></span></span>
<p>The components of the equation are:</p>
<ul>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mi>π</mi></msub><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">v_{\pi}(s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em">π</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mclose">)</span></span></span></span>: the value of state <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">s</span></span></span></span> under policy <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal" style="margin-right:0.03588em">π</span></span></span></span>, this is what we want to compute.</li>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo stretchy="false">(</mo><mi>a</mi><mi mathvariant="normal">∣</mi><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\pi(a|s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.03588em">π</span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mord">∣</span><span class="mord mathnormal">s</span><span class="mclose">)</span></span></span></span>: the probability of taking action <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi></mrow><annotation encoding="application/x-tex">a</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">a</span></span></span></span> in state <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">s</span></span></span></span>. This is called the policy.</li>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo stretchy="false">(</mo><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo separator="true">,</mo><mi>r</mi><mi mathvariant="normal">∣</mi><mi>s</mi><mo separator="true">,</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p(s',r|s,a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.0019em;vertical-align:-0.25em"></span><span class="mord mathnormal">p</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.02778em">r</span><span class="mord">∣</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span>: the probability of transitioning to state <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup></mrow><annotation encoding="application/x-tex">s'</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7519em"></span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span></span></span></span> and receiving reward <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi></mrow><annotation encoding="application/x-tex">r</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal" style="margin-right:0.02778em">r</span></span></span></span> after taking action <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi></mrow><annotation encoding="application/x-tex">a</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">a</span></span></span></span> in state <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">s</span></span></span></span>.</li>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>γ</mi></mrow><annotation encoding="application/x-tex">\gamma</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em"></span><span class="mord mathnormal" style="margin-right:0.05556em">γ</span></span></span></span>: the discount rate, which determines the importance of future rewards and is a value between 0 and 1. In our case it is set to 0.9.</li>
</ul>
<p>Now the example proceeds by giving us the policy: the agent selects each action with equal probability <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo stretchy="false">(</mo><mi>a</mi><mi mathvariant="normal">∣</mi><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><mn>4</mn></mfrac></mrow><annotation encoding="application/x-tex">\pi(a|s) = \frac{1}{4}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.03588em">π</span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mord">∣</span><span class="mord mathnormal">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.1901em;vertical-align:-0.345em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8451em"><span style="top:-2.655em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">4</span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.394em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>, so we can simplify the equation:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mi>π</mi></msub><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><mn>4</mn></mfrac><munder><mo>∑</mo><mi>a</mi></munder><munder><mo>∑</mo><mrow><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo separator="true">,</mo><mi>r</mi></mrow></munder><mi>p</mi><mo stretchy="false">(</mo><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo separator="true">,</mo><mi>r</mi><mi mathvariant="normal">∣</mi><mi>s</mi><mo separator="true">,</mo><mi>a</mi><mo stretchy="false">)</mo><mo stretchy="false">[</mo><mi>r</mi><mo>+</mo><mi>γ</mi><msub><mi>v</mi><mi>π</mi></msub><mo stretchy="false">(</mo><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">)</mo><mo stretchy="false">]</mo><mo separator="true">,</mo><mspace width="1em"></mspace><mi mathvariant="normal">∀</mi><mi>s</mi><mo>∈</mo><mi>S</mi></mrow><annotation encoding="application/x-tex">v_{\pi}(s) = \frac{1}{4} \sum_{a} \sum_{s',r} p(s',r|s,a) [r + \gamma v_{\pi}(s')], \quad \forall s \in S</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em">π</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.7515em;vertical-align:-1.4301em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em"><span style="top:-2.314em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">4</span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.677em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.25em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.856em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.6828em"><span style="top:-2.786em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mpunct mtight">,</span><span class="mord mathnormal mtight" style="margin-right:0.02778em">r</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.4301em"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">p</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8019em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal" style="margin-right:0.02778em">r</span><span class="mord">∣</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">a</span><span class="mclose">)</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.02778em">r</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.0519em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.05556em">γ</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em">π</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8019em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mclose">)]</span><span class="mpunct">,</span><span class="mspace" style="margin-right:1em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord">∀</span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.05764em">S</span></span></span></span></span>
<p>Because the environment is deterministic, for each state-action pair there is exactly one next state <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup></mrow><annotation encoding="application/x-tex">s'</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7519em"></span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span></span></span></span> and reward (probability 1). Therefore the update simplifies to:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mi>π</mi></msub><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><mn>4</mn></mfrac><munder><mo>∑</mo><mi>a</mi></munder><mo stretchy="false">[</mo><mi>r</mi><mo>+</mo><mi>γ</mi><msub><mi>v</mi><mi>π</mi></msub><mo stretchy="false">(</mo><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">)</mo><mo stretchy="false">]</mo></mrow><annotation encoding="application/x-tex">v_{\pi}(s) = \frac{1}{4} \sum_{a} [r + \gamma v_{\pi}(s')]</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em">π</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.5714em;vertical-align:-1.25em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em"><span style="top:-2.314em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">4</span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.677em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.05em"><span style="top:-1.9em;margin-left:0em"><span class="pstrut" style="height:3.05em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.05em"><span class="pstrut" style="height:3.05em"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.25em"><span></span></span></span></span></span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.02778em">r</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.0519em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.05556em">γ</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em">π</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8019em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mclose">)]</span></span></span></span></span>
<p>Using this formula we iteratively update the value function for each state until convergence up to a certain tolerance.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-implementation">The implementation<a href="https://davidelettieri.it/2025/10/19/sutton-barto-gridworld#the-implementation" class="hash-link" aria-label="Direct link to The implementation" title="Direct link to The implementation" translate="no">​</a></h2>
<p>Regarding the implementation, I mostly followed the sample lisp code provided by the authors at <a href="http://incompleteideas.net/book/code/gridworld5x5.lisp" target="_blank" rel="noopener noreferrer" class="">http://incompleteideas.net/book/code/gridworld5x5.lisp</a>. However I used clearer variable names, an enum for the actions, a better <code>next-state</code> and <code>full-backup</code> function and other minor improvements. If you look at the original <code>full-backup</code> it is actually also computing the <code>next-state</code> for a subset of cases, I decided to handle all cases in my <code>NextState</code> method and use the <code>FullBackup</code> only to compute the value of a given state-action pair.</p>
<p>Some of the Lisp code's complexity — which I preserved in the C# port — is the mapping between state indices (0–24) and grid coordinates (row and column). It's not clear why the original maps states to indices this way; I kept the mapping for fidelity to the original implementation.</p>
<p>As a side note, I executed the lisp code to validate the results and the methods I ported to C# using <a href="https://www.sbcl.org/" target="_blank" rel="noopener noreferrer" class="">SBCL</a> and apparently a function was missing so I added it and provided an updated lisp version in my repo <a href="https://github.com/davidelettieri/sutton-barto-reinforcement-learning/blob/main/gridworld/source.lisp" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<p>I decided to use a <code>GridWorld</code> class to hold the global state and the required functions.</p>
<p>Looking at the simplified Bellman equation we can see that we need to compute <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>s</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup></mrow><annotation encoding="application/x-tex">s'</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7519em"></span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em"><span style="top:-3.063em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span></span></span></span> given a starting state and an action, this is implemented in the <code>NextState</code> method of the GridWorld class:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token return-type class-name keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">NextState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">int</span><span class="token plain"> state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Action</span><span class="token plain"> action</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">state </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> _specialStateA</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> _specialStateAPrime</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">state </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> _specialStateB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> _specialStateBPrime</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// OffGrid returns true if the action would take the agent off the grid</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">OffGrid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> state</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">row</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> col</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">CoordinatesFromState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">state</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> action </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Action</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">East </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">StateFromCoordinates</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">row</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> col </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Action</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">South </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">StateFromCoordinates</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">row </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> col</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Action</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">West </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">StateFromCoordinates</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">row</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> col </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Action</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">North </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">StateFromCoordinates</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">row </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> col</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _ </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">ArgumentOutOfRangeException</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">nameof</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">action</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Invalid action"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The sum formula is adding one element for each action, the single element for a given action and state is computed in the <code>FullBackup</code> method:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token return-type class-name keyword" style="color:#00009f">double</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">FullBackup</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">int</span><span class="token plain"> state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Action</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> nextState </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">NextState</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> reward </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> state </span><span class="token keyword" style="color:#00009f">switch</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _ </span><span class="token keyword" style="color:#00009f">when</span><span class="token plain"> state </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> _specialStateA </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _ </span><span class="token keyword" style="color:#00009f">when</span><span class="token plain"> state </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> _specialStateB </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// implicitly handles off-grid moves</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _ </span><span class="token keyword" style="color:#00009f">when</span><span class="token plain"> nextState </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> state </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _ </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> reward </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_gamma </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> _v</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">nextState</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The implementation of the value function is the following. Consider that we have 4 actions so average is dividing by 4:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">double</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ValueFunction</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">int</span><span class="token plain"> state</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> Enum</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-method function" style="color:#d73a49">GetValues</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&lt;</span><span class="token generic-method generic class-name">Action</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Select</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">a </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">FullBackup</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Average</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>The rest of the implementation is almost a 1-1 mapping from the lisp code to C#. The value function is updated in a loop until convergence.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-run-the-sample">How to run the sample<a href="https://davidelettieri.it/2025/10/19/sutton-barto-gridworld#how-to-run-the-sample" class="hash-link" aria-label="Direct link to How to run the sample" title="Direct link to How to run the sample" translate="no">​</a></h2>
<ul>
<li class="">
<p>Clone and run the sutton-barto-reinforcement-learning repository:</p>
<ul>
<li class="">git clone <a href="https://github.com/davidelettieri/sutton-barto-reinforcement-learning.git" target="_blank" rel="noopener noreferrer" class="">https://github.com/davidelettieri/sutton-barto-reinforcement-learning.git</a></li>
<li class="">cd sutton-barto-reinforcement-learning/gridworld</li>
<li class="">dotnet run -c Release</li>
</ul>
</li>
<li class="">
<p>The app prints the value function after convergence; compare it with the book’s Figure 3.2.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="grid-diagram-and-state-mapping">Grid diagram and state mapping<a href="https://davidelettieri.it/2025/10/19/sutton-barto-gridworld#grid-diagram-and-state-mapping" class="hash-link" aria-label="Direct link to Grid diagram and state mapping" title="Direct link to Grid diagram and state mapping" translate="no">​</a></h2>
<p>To make the indexing clear, here's the 5x5 grid used in the example (rows increase downward, columns increase to the right). Special states A and B and their primes A' and B' are shown in the grid where applicable.</p>
<table><thead><tr><th></th><th style="text-align:center">Col 0</th><th style="text-align:center">Col 1</th><th style="text-align:center">Col 2</th><th style="text-align:center">Col 3</th><th style="text-align:center">Col 4</th></tr></thead><tbody><tr><td><strong>Row 0</strong></td><td style="text-align:center">0</td><td style="text-align:center">1 (A)</td><td style="text-align:center">2</td><td style="text-align:center">3 (B)</td><td style="text-align:center">4</td></tr><tr><td><strong>Row 1</strong></td><td style="text-align:center">5</td><td style="text-align:center">6</td><td style="text-align:center">7</td><td style="text-align:center">8</td><td style="text-align:center">9</td></tr><tr><td><strong>Row 2</strong></td><td style="text-align:center">10</td><td style="text-align:center">11</td><td style="text-align:center">12</td><td style="text-align:center">13 (B')</td><td style="text-align:center">14</td></tr><tr><td><strong>Row 3</strong></td><td style="text-align:center">15</td><td style="text-align:center">16</td><td style="text-align:center">17</td><td style="text-align:center">18</td><td style="text-align:center">19</td></tr><tr><td><strong>Row 4</strong></td><td style="text-align:center">20</td><td style="text-align:center">21 (A')</td><td style="text-align:center">22</td><td style="text-align:center">23</td><td style="text-align:center">24</td></tr></tbody></table>]]></content:encoded>
            <category>c#</category>
            <category>reinforcement-learning</category>
        </item>
        <item>
            <title><![CDATA[Webhooks packages to simplify payload signing]]></title>
            <link>https://davidelettieri.it/2025/09/21/webhooks-packages</link>
            <guid>https://davidelettieri.it/2025/09/21/webhooks-packages</guid>
            <pubDate>Sun, 21 Sep 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A few weeks back I became aware of an attempt to create a technology agnostic standard to send and receive webhooks securely. The proposal is here.]]></description>
            <content:encoded><![CDATA[<p>A few weeks back I became aware of an attempt to create a technology agnostic standard to send and receive webhooks securely. The proposal is <a href="https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<p>In my opinion, the standard is straightforward and non-controversial. The only part that is mandatory is the signing part, other parts are optional and somehow suggesting best practices.</p>
<p>In the standard-webhooks repo you'll find multiple sample implementations and some links to community implementations including one for C#. I was researching webhooks standards to implement my own packages and to play a bit with copilot agent on github. So I decided to go ahead and do it.</p>
<p>The end result is this <a href="https://github.com/davidelettieri/webhooks/tree/main" target="_blank" rel="noopener noreferrer" class="">repo</a> which contains:</p>
<ul>
<li class="">two packages: one to send webhooks, one to receive it</li>
<li class="">a sample aspire application to see how all of this works</li>
<li class="">some tests to verify implementation and interoperability with existing community .NET implementation of standard webhooks</li>
</ul>
<p>I used copilot agent mostly to iterate over security features and less known (to me!) cryptographic operations. Overall I'm happy with the result, it's a simple implementation, there are plenty of validations on header number, headers' values length, body length etc.</p>
<p>Please note that it is a partial implementation because it supports only symmetric signature and it is based over a pre-shared key, but the packages do not provide any key management support.</p>
<p>Overall a small exercise and there are multiple pieces to be built in order to have a fully functional webhooks system. If we assume APIs to setup everything we should have</p>
<ul>
<li class="">[Publisher side] Configuration API: clients interested in receiving webhooks should be able to configure listening endpoints, possibly including the pre-shared key</li>
<li class="">[Publisher side] Retry with backoff: we want to publish webhooks with a "at least once" semantic. Retries with reasonable backoff and persistence are a must. Regardless of backoff we probably want to stop after a certain number of retries.</li>
<li class="">[Publisher side] Webhooks history: we should provide a suitable endpoint to provide a list of webhooks published during a time window for cases when consumers are unable to consume webhooks for a long time or they become uncertain of which webhooks were processed correctly.</li>
<li class="">[Receiver side] Fast-ACK: when receiving webhooks we should be able to acknowledge as fast as possible to avoid timeout and automatic retries to be triggered. This means that if we need to trigger some business process when receiving webhooks we should do it asynchronously.</li>
<li class="">[Receiver side] Idempotency, it will protect from replay attacks and it will avoid that unintended duplicated webhooks will be processed twice.</li>
</ul>
<p>In my professional experience I worked on most (if not all) of the features in several companies. I will try to continue the work on the repo to implement all of this, with reasonable interfaces but selecting technologies I like.</p>
<p>If we need to store webhooks to be able to retry after application reboots, what kind of storage do we use? We could use a document db or a relational database, or something like <a href="https://www.hangfire.io/" target="_blank" rel="noopener noreferrer" class="">Hangfire</a>.</p>
<p>Should we use event sourcing to store the webhook payload, something like a <code>WebhookReceived</code> event, acknowledge to the publisher and enable async processing? Can we use a distributed cache to implement idempotency?</p>
<p>I think most of the remaining parts, if not all, will be strongly opinionated and possibly depending on the existing stack of the application we are working on. I will try to implement all using pieces that I like.</p>
<p>If you are interested in seeing something in particular of if you think I missed something, let me know using the comment box below or sending me a message through email / linkedin.</p>]]></content:encoded>
            <category>c#</category>
            <category>webhooks</category>
            <category>ASP.NET Core</category>
        </item>
        <item>
            <title><![CDATA[Announcing the new comment system]]></title>
            <link>https://davidelettieri.it/2025/08/18/comments-announcement</link>
            <guid>https://davidelettieri.it/2025/08/18/comments-announcement</guid>
            <pubDate>Mon, 18 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[After thinking about it for some time I decided to add a comment system to the blog. What I hope is that I will get valuable feedback from readers, which will help me improve the content, my understanding of the topics I write about, and the overall quality of the blog.]]></description>
            <content:encoded><![CDATA[<p>After thinking about it for some time I decided to add a comment system to the blog. What I hope is that I will get valuable feedback from readers, which will help me improve the content, my understanding of the topics I write about, and the overall quality of the blog.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-was-built">How It Was Built<a href="https://davidelettieri.it/2025/08/18/comments-announcement#how-it-was-built" class="hash-link" aria-label="Direct link to How It Was Built" title="Direct link to How It Was Built" translate="no">​</a></h3>
<p>I decided all of this while on a beach, in Italy and I didn't have access to a coding environment. So I decided to treat myself with a copilot pro license and try to get it implemented by the copilot agent.</p>
<p>Somehow it worked out, I realized quickly that I didn't give enough information to complete the task, but with some back-and-forth, we got there in the end.</p>
<p>The whole implementation took 4 iterations, <a href="https://github.com/davidelettieri/davidelettieri.it/pull/69" target="_blank" rel="noopener noreferrer" class="">here's the PR</a> with my requests to copilot, at first the comment box wasn't rendering and copilot chose some parameters that didn't match what I wanted for giscus. Strangely enough, I provided a <code>script</code> tag and asked copilot to extrapolate the values and use them in the code but it didn't work. Then I asked in the copilot chat to extrapolate the values to a table and I provided it to copilot. This worked well. Last point I asked copilot to reposition the comment box. It worked right away.</p>
<p>Key points:</p>
<ul>
<li class="">copilot introduced an error with a docusaurus component, it wasn't able to fix it in 2 iterations and it wasn't really needed. I asked to remove it.</li>
<li class="">I forgot to include from the start the parameters and the position for the comment box. Maybe given at the beginning the result could have been  achieved faster.</li>
<li class="">copilot changed my <code>yarn.lock</code> by replacing the registry <code>https://registry.yarnpkg.com</code> with <code>https://registry.npmjs.org</code>. I regenerated <code>yarn.lock</code> from scratch. I doesn't make any difference however I would have preferred not having a huge diff on the <code>yarn.lock</code> file wondering what might have happened.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="caveats-of-the-comments-system">Caveats of the comments system.<a href="https://davidelettieri.it/2025/08/18/comments-announcement#caveats-of-the-comments-system" class="hash-link" aria-label="Direct link to Caveats of the comments system." title="Direct link to Caveats of the comments system." translate="no">​</a></h3>
<p>The system I chose is <a href="https://giscus.app/it" target="_blank" rel="noopener noreferrer" class="">giscus</a> which is a github-based comment system, so anyone who wants to add a comment will need a github account. I know this won't work for all people however I hope it will work for most people.</p>
<p>Finally I can say: let me know what you think in the comment box!</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ray tracing in one weekend in go]]></title>
            <link>https://davidelettieri.it/2025/06/16/ray-tracing-in-one-weekend</link>
            <guid>https://davidelettieri.it/2025/06/16/ray-tracing-in-one-weekend</guid>
            <pubDate>Mon, 16 Jun 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[I had the Ray Tracing in One Weekend book in my todo list for a long time and I had finally the time to go through it.]]></description>
            <content:encoded><![CDATA[<p>I had the <a href="https://raytracing.github.io/books/RayTracingInOneWeekend.html" target="_blank" rel="noopener noreferrer" class=""><em>Ray Tracing in One Weekend</em></a> book in my todo list for a long time and I had finally the time to go through it.</p>
<p>There is not much to say, except than rather unusually I used go instead of C# to go through the book. The code is a rather simple port from the C++ original, my only addition was a render method that used goroutines and channels to speed up the execution. It works fairly well and tops up the CPUs on my desktop machine.</p>
<p>The <a href="https://github.com/davidelettieri/raytracing-one-weekend-go" target="_blank" rel="noopener noreferrer" class="">repo</a> contains the image with 10 samples per pixel and the image with 100 samples per pixel. The quality difference is evident! To check it out you need to clone the repo, or download the raw files, and have a ppm image viewer installed.</p>]]></content:encoded>
            <category>go</category>
            <category>ray-tracing</category>
        </item>
        <item>
            <title><![CDATA[Multi armed bandit exercise 2.5 with C#]]></title>
            <link>https://davidelettieri.it/2025/05/01/multi-armed-bandit-ex-2.5-csharp</link>
            <guid>https://davidelettieri.it/2025/05/01/multi-armed-bandit-ex-2.5-csharp</guid>
            <pubDate>Thu, 01 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Recently I tried to code the 10 armed testbed example from chapter 2 of Sutton and Barto Reinforcement Learning: an introduction book.]]></description>
            <content:encoded><![CDATA[<p>Recently I tried to code <a class="" href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp">the 10 armed testbed</a> example from chapter 2 of Sutton and Barto <a href="http://www.incompleteideas.net/book/the-book-2nd.html" target="_blank" rel="noopener noreferrer" class="">Reinforcement Learning: an introduction</a> book.</p>
<p>The chapter continues introducing new theory elements and strategies to improve the approach shown in the 10 armed example. In particular, one of the points is about non-stationary problems.</p>
<p>The 10 armed testbed was a stationary problem, the probability distributions of the different actions don't change over time. If you remember the sample, at the beginning of the round we computed 10 random values, those values are then used to be the mean of a normal distribution from which we will pick the rewards at each step. The constant part is that this normal distributions don't change from a step to another, they stay the same for the whole round execution.</p>
<p>The focus of the exercise is to understand how the estimated reward computation impacts the performance of the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>-greedy strategy. In the 10 armed testbed, the estimate reward was computed averaging the rewards obtained from each action when selected. Note that this approach consider each reward with the same relative value, however in a non-stationary problem, where probability distributions change over time we would like to give more weight or importance to more recent rewards because they represent more realistically the current distribution the reward is generated from.</p>
<p>The text of the exercise is</p>
<blockquote>
<p>Design and conduct an experiment to demonstrate the
difficulties that sample-average methods have for nonstationary problems. Use a modified
version of the 10-armed testbed in which all the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>q</mi><mo lspace="0em" rspace="0em">∗</mo></msub><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">q_{*}(a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1757em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∗</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span> start out equal and then take
independent random walks (say by adding a normally distributed increment with mean 0
and standard deviation 0.01 to all the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>q</mi><mo lspace="0em" rspace="0em">∗</mo></msub><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">q_{*}(a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1757em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∗</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span> on each step). Prepare plots like Figure 2.2
for an action-value method using sample averages, incrementally computed, and another
action-value method using a constant step-size parameter, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal" style="margin-right:0.0037em">α</span></span></span></span> = 0.1. Use <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi><mo>=</mo><mn>0.1</mn></mrow><annotation encoding="application/x-tex">\epsilon = 0.1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">0.1</span></span></span></span> and
longer runs, say of 10,000 steps.</p>
</blockquote>
<p>Figure 2.2 refers to the <strong>average reward graph</strong> and <strong>the best arm selection rate graph</strong>, the same graphs I produced in the previous <a class="" href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp">post</a>. The <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi><mo>=</mo><mn>0.1</mn></mrow><annotation encoding="application/x-tex">\epsilon=0.1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">0.1</span></span></span></span> refers to the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>-greedy strategy to be used, both in the case of sample averages and in the constant step-size parameter.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-reward-estimation-formula">The reward estimation formula<a href="https://davidelettieri.it/2025/05/01/multi-armed-bandit-ex-2.5-csharp#the-reward-estimation-formula" class="hash-link" aria-label="Direct link to The reward estimation formula" title="Direct link to The reward estimation formula" translate="no">​</a></h2>
<p>The sample average estimation can be naively computed by keeping track of all the rewards for an action and compute the average. However, as the book describes clearly, we can compute the average only by using the current reward, the previous estimate and the number of times the action has been selected. With this approach we have a computational advantage since we don't need to store the rewards for all steps and we need just a few operations to compute the new estimate.</p>
<p>If we denote the estimate at <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em"></span><span class="mord mathnormal">i</span></span></span></span>th as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">Q_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span>, the reward as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">R_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em"><span style="top:-2.55em;margin-left:-0.0077em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> then the formula is:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>Q</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><msub><mi>Q</mi><mi>n</mi></msub><mo>+</mo><mfrac><mn>1</mn><mi>n</mi></mfrac><mo stretchy="false">[</mo><msub><mi>R</mi><mi>n</mi></msub><mo>−</mo><msub><mi>Q</mi><mi>n</mi></msub><mo stretchy="false">]</mo></mrow><annotation encoding="application/x-tex">Q_{n+1} = Q_n + \frac{1}{n}[R_n-Q_n]</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8917em;vertical-align:-0.2083em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2083em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em"><span style="top:-2.314em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.677em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mopen">[</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0077em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mclose">]</span></span></span></span></span>
<p>Once we have this we can also see how the estimate is computed with constant-step size parameter <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal" style="margin-right:0.0037em">α</span></span></span></span>:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>Q</mi><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow></msub><mo>=</mo><msub><mi>Q</mi><mi>n</mi></msub><mo>+</mo><mi>α</mi><mo stretchy="false">[</mo><msub><mi>R</mi><mi>n</mi></msub><mo>−</mo><msub><mi>Q</mi><mi>n</mi></msub><mo stretchy="false">]</mo></mrow><annotation encoding="application/x-tex">Q_{n+1} = Q_n + \alpha[R_n-Q_n]</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8917em;vertical-align:-0.2083em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.2083em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.0037em">α</span><span class="mopen">[</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0077em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mclose">]</span></span></span></span></span>
<p>The two formulas are almost the same, the difference <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>R</mi><mi>n</mi></msub><mo>−</mo><msub><mi>Q</mi><mi>n</mi></msub></mrow><annotation encoding="application/x-tex">R_n-Q_n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0077em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> is multiplied by <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi mathvariant="normal">/</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">1/n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord">1/</span><span class="mord mathnormal">n</span></span></span></span> in one case and by a constant value <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal" style="margin-right:0.0037em">α</span></span></span></span> in the other.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-implementation">The implementation<a href="https://davidelettieri.it/2025/05/01/multi-armed-bandit-ex-2.5-csharp#the-implementation" class="hash-link" aria-label="Direct link to The implementation" title="Direct link to The implementation" translate="no">​</a></h2>
<p>If you checked the previous example I implemented you'll see that the code is mostly the same. I have to support:</p>
<ul>
<li class="">non-stationary rewards distributions</li>
<li class="">different strategies to compute the estimate reward</li>
</ul>
<p>I don't want to make the previous example too complex and add abstractions to plug in different implementation just to not duplicate code. For both examples I want an easy to follow, low abstraction implementation that I can understand easily in a year from now when all the context I have is lost. However I need to be able to plug in two different strategies for estimate computation, so in that case only I'll use some kind of abstraction:</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">delegate</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">double</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">UpdateEstimatedReward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> currentEstimatedReward</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> reward</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name keyword" style="color:#00009f">int</span><span class="token plain"> armSelectedCount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>A delegate to capture the function signature of the update formula. The <code>armSelectedCount</code> parameter (I couldn't think of a better name) correspond to the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">n</span></span></span></span> of the formulas we have above.</p>
<p>And the two formulas translate to</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">UpdateEstimatedReward</span><span class="token plain"> sampleAverage </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">currentEstimatedReward</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> reward</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> armSelectedCount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    currentEstimatedReward </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">reward </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> currentEstimatedReward</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> armSelectedCount</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token return-type class-name">UpdateEstimatedReward</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">constantStepSize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">double</span><span class="token plain"> alpha</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">currentEstimatedReward</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> reward</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> _</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        currentEstimatedReward </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> alpha </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">reward </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> currentEstimatedReward</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>The <code>sampleAverage</code> is just an instance of the delegate while the <code>constantStepSize</code> is a function producing an instance of the delegate. That's because we have the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal" style="margin-right:0.0037em">α</span></span></span></span> parameter that needs to be fixed in order to have a concrete update formula. Note also that the third parameter, <code>armSelectedCount</code>, is ignored in the <code>constantStepSize</code> definition.</p>
<p>Regarding the non-stationary part, the exercise text says that we start with equal <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>q</mi><mo>∗</mo></msub><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">q_*(a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1757em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mbin mtight">∗</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span> and the all of them take independent random walks. In the ten armed testbed example, the reward for each actions was a distribution, should be the same here? We have a distribution with variating mean or we should just pick <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>q</mi><mo>∗</mo></msub><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">q_*(a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1757em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mbin mtight">∗</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span> as reward for any step given that it is already changing? I do not know to be honest what the expected approach here, my decision was to go with distributions with changing mean value.</p>
<p>In order to implement correctly the best arm selection rate we have to notice that the best arm is not defined once at beginning but at each step we could end up with a different best arm so we need to compute which one is the best again.</p>
<figure><img style="margin:0 auto;display:block" alt="The average reward per step" src="https://davidelettieri.it/img/ex2-5_average_reward.png"><figcaption>The average reward per step</figcaption></figure>
<figure><img style="margin:0 auto;display:block" alt="The best arm selection rate per step" src="https://davidelettieri.it/img/ex2-5_best_arm_selection_rate.png"><figcaption>The best arm selection rate per step</figcaption></figure>]]></content:encoded>
            <category>c#</category>
            <category>reinforcement-learning</category>
            <category>k-armed bandit problem</category>
        </item>
        <item>
            <title><![CDATA[Ten armed testbed for the Bandit problem with C#]]></title>
            <link>https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp</link>
            <guid>https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp</guid>
            <pubDate>Sun, 27 Apr 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[I'm continuing my attempt to reproduce examples from Reinforcement Learning: An Introduction book using C#.]]></description>
            <content:encoded><![CDATA[<p>I'm continuing my attempt to reproduce examples from <a href="http://incompleteideas.net/book/the-book-2nd.html" target="_blank" rel="noopener noreferrer" class=""><strong>Reinforcement Learning: An Introduction</strong></a> book using C#.</p>
<p>In a <a class="" href="https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp">previous post</a> I reproduced the tic-tac-toe example with some improvements and clarification with respect to the original text. I think it's worth taking a look at it.</p>
<p>Today I'm reproducing the ten armed testbed for the Bandit problem, in particular I want to reproduce the two graphs showing the average reward improvements and the selection rate of the best arm.</p>
<p>The problem, as stated in the book is the following:</p>
<blockquote>
<p>You are faced repeatedly with a choice among k different options, or actions. After each choice you receive a numerical reward chosen from a stationary probability distribution that depends on the action you selected. Your objective is to maximize the expected total reward over some time period, for example, over 1000 action selections, or time steps.</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="10-armed-testbed">10 armed testbed<a href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp#10-armed-testbed" class="hash-link" aria-label="Direct link to 10 armed testbed" title="Direct link to 10 armed testbed" translate="no">​</a></h2>
<p>One key point to understand to follow the ten armed (k=10) testbed is that the total reward is never computed nor analized in the example itself. The underlying intuition is that we want to find the best action available and select that action as much as possible. Ideally everytime. By being able to select the best action, we will automatically optimize the total reward.</p>
<p>Once selected the value of <code>k=10</code>, we have to define the probability distribution for each action. That is done by using a normal distribution with <code>mean=0</code> and <code>variance=1</code>, we pick 10 samples from this distribution and each sample will be the mean value of a normal distribution with <code>variable=1</code>. We end up with an array of 10 normal distributions, each time we select action <code>i</code> we will pick the <code>i-th</code> distribution and get a sample value from that distribution.</p>
<p>Given that we don't know the probability distribution assigned to each action we have to base our strategies on estimates values. Each time we select an action, we get an actual reward value and we can improve our estimate for that action. We iterate this process trying to improve our estimates. We start with an estimate of zero for all actions. Each of these selection and update of estimates is called a <strong>step</strong>. A <strong>round</strong> comprises multiple <strong>steps</strong>. In the example provided in the book, we found 2000 <strong>rounds</strong> of 1000 <strong>step</strong> each.</p>
<p>To produce the graphs presented in the book we need to compute:</p>
<ul>
<li class="">for each step, the average reward over the different rounds. For each round, we keep track of reward of step <code>i</code>. At the end we sum all rewards and we divide by the number of rounds.</li>
<li class="">for each step, the best arm selection rate. For each step of each round, we keep track of how many times we selected the best action. At the end we sum all values and we divide by the number of rounds. Please remember that we know which arm is best, because we are creating the distributions for each arm. This information cannot be used during the learning process but we can use it to evaluate performances on the testbed.</li>
</ul>
<p>One point that remains to define is how we select the action. It is evident that we would like to try all of them multiple times so that we can build a reasonable estimate of the value of each action. For example we could select each action in a round-robin fashion and repeat until we complete all steps. This would give us a uniform approach for updating the estimated values, however the best action will be selected roughly <code>1/k</code> times, in our case corresponding to 10% of the times. That is not very good for the overall performance of the round.</p>
<p>The books suggests three different strategies:</p>
<ul>
<li class="">greedy: we always select the action with the best estimate</li>
<li class=""><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>-greedy: on a subset of cases we select a random action, on the remaining ones we select the best strategy:<!-- -->
<ul>
<li class="">10% of the selections is random (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>=0.1)</li>
<li class="">1% of the selections is random (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>=0.01)</li>
</ul>
</li>
</ul>
<p>Ties are resolved by picking any of the actions with the same expected reward. We already noted that on each step we perform a selection and an update of the estimates. This is true regardless of the strategy, in the tic-tac-toe example we saw that we learned only when the action was selected based on the value table but not when selected randomly. This is not the case here where learning when selecting randomly is the very base for actual improvements.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="greedy-strategy">Greedy strategy<a href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp#greedy-strategy" class="hash-link" aria-label="Direct link to Greedy strategy" title="Direct link to Greedy strategy" translate="no">​</a></h3>
<p>Let's consider for a moment how the greedy behaves on some cases.</p>
<p>We are at step 0, all estimates are 0 so we need to pick a random action between 0-9. Let's say we pick 0:</p>
<ul>
<li class="">if the actual reward is negative, the estimate for 0 will become negative and we won't select 0 in the next step</li>
<li class="">if the actual reward is positive, the estimate for 0 will be positive and we will select 0 in the next step. Actually we will continue to select 0 until the estimate become 0 or less. If it is 0, depending on how the tie is resolved we might continue with 0.</li>
</ul>
<p>From this it's clear that if 0 is not optimal we might end up stuck with 0 for several steps until we are able to evaluate another action.</p>
<p>An observation that we could make is that we could force the greedy strategy to test at least once each action by starting with a default estimate of <code>double.MaxValue</code>. We know that the reward for all actions will be lower than <code>double.MaxValue</code> so at the first 10 steps all actions will be tested, afterwards we will continue with the action that performed the best on the first 10 steps.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="epsilon-greedy-strategy"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>-greedy strategy<a href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp#epsilon-greedy-strategy" class="hash-link" aria-label="Direct link to epsilon-greedy-strategy" title="Direct link to epsilon-greedy-strategy" translate="no">​</a></h3>
<p>With the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>-greedy strategy we are never sure if we are picking the best action, according to our current knowledge, or a random one. However then random one will give us opportunities to improve our estimates.</p>
<p>An improvement over this strategy could be to make <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span> smaller as we progress further into our round. The more steps we perform, the better the estimates we have, the lesser need for exploration we have.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="some-additional-comments">Some additional comments<a href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp#some-additional-comments" class="hash-link" aria-label="Direct link to Some additional comments" title="Direct link to Some additional comments" translate="no">​</a></h3>
<p>The book notes (bold is mine):</p>
<blockquote>
<p>The advantage of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>-greedy over greedy methods depends on the task. For example,
suppose the reward variance had been larger, say 10 instead of 1. With noisier rewards
it takes more exploration to find the optimal action, and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ϵ</mi></mrow><annotation encoding="application/x-tex">\epsilon</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em"></span><span class="mord mathnormal">ϵ</span></span></span></span>-greedy methods should fare
even better relative to the greedy method. <strong>On the other hand, if the reward variances
were zero, then the greedy method would know the true value of each action after trying
it once. In this case the greedy method might actually perform best because it would
soon find the optimal action and then never explore.</strong> But even in the deterministic case
there is a large advantage to exploring if we weaken some of the other assumptions.</p>
</blockquote>
<p>I want to comment on the bold section, because I don't fully agree with what is said there. Let's consider for a moment a ten armed testbed which actions have stationary rewards as <code>[0.05 0.1 0.2 0.3 0.4 0.5 0.7 0.8 0.9]</code> and let's think how the greedy performs.</p>
<p>Given that:</p>
<ul>
<li class="">estimate won't change once updated</li>
<li class="">we start with all estimates equal to <code>0</code></li>
<li class="">we always select the best</li>
</ul>
<p>the first action selected will change its estimate to a value greater than <code>0</code> and it will always be selected without any further exploration. This is a rather artificial example however what is true is that the greedy strategy will always select an action with positive reward once it has found any.</p>
<p><strong>So when the greedy strategy will indeed find the best arm in the stationary case?</strong> One case is when the best arm is the only one with a positive reward. Another one is when all arms have negative reward because it will pick one by one all of them on the first steps. Since in case of ties there is some randomization at play, the greedy strategy can select the best arm in other cases.</p>
<p>Different result can be obtained if we change the initial estimate of the actions. Again selecting <code>double.MaxValue</code> as default instead of <code>0</code> would force the greedy strategy to select at least once all the arm and then know exactly which one is the best and continue with that.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="code">Code<a href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp#code" class="hash-link" aria-label="Direct link to Code" title="Direct link to Code" translate="no">​</a></h4>
<p>I implemented of all this in the <a href="https://github.com/davidelettieri/sutton-barto-reinforcement-learning" target="_blank" rel="noopener noreferrer" class="">https://github.com/davidelettieri/sutton-barto-reinforcement-learning</a> repo. I think I left enough comments to allow an easy read of the code, if that's not the case please contact me I'll be happy to add more or explain better if needed.</p>
<p>The graphs are implemented using <a href="https://scottplot.net/" target="_blank" rel="noopener noreferrer" class="">https://scottplot.net/</a>, you might need to install additional packages, please follow the documentation for more details. On my Fedora 42, at the time of writing, the code works as it is and produce the following graphs:</p>
<figure><img style="margin:0 auto;display:block" alt="The average reward per step, per strategy" src="https://davidelettieri.it/img/average_reward.png"><figcaption>The average reward per step, per strategy</figcaption></figure>
<figure><img style="margin:0 auto;display:block" alt="The best arm selection rate per step, per strategy" src="https://davidelettieri.it/img/best_arm_selection_rate.png"><figcaption>The best arm selection rate per step, per strategy</figcaption></figure>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="initializing-default-estimates-to-doublemaxvalue">Initializing default estimates to double.MaxValue<a href="https://davidelettieri.it/2025/04/27/ten-armed-testbed-with-c-sharp#initializing-default-estimates-to-doublemaxvalue" class="hash-link" aria-label="Direct link to Initializing default estimates to double.MaxValue" title="Direct link to Initializing default estimates to double.MaxValue" translate="no">​</a></h3>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>When I wrote all of this, I didn't read paragraph 2.6 and I thought that the dependance on the default estimate should have been discussed already. The authors of the book disagree on this and discussed right afterwards in <strong>2.6 Optimistic Initial Values</strong>. I, of course, recommend to read the book which is available for free <a href="http://www.incompleteideas.net/book/the-book-2nd.html" target="_blank" rel="noopener noreferrer" class="">here</a>.</p></div></div>
<p>As noted above a couple of times, setting the default estimate to <code>double.MaxValue</code> will force exploration at initial steps for all strategies. The performance of the average reward improves for all strategies, possibly excluding the initial exploration which is quite visible on the graph as brief (10 steps) almost horizontal progress on the three lines. It is noticeable also how the three strategies behave almost with the same performance on the average reward. The graph for the best arm selection rate is rather different from the previous case, showing again more similaties between the three strategies.</p>
<figure><img style="margin:0 auto;display:block" alt="The average reward per step, per strategy using double.MaxValue as default estimate" src="https://davidelettieri.it/img/average_reward_max_value.png"><figcaption>The average reward per step, per strategy using double.MaxValue as default estimate</figcaption></figure>
<figure><img style="margin:0 auto;display:block" alt="The best arm selection rate per step, per strategy using double.MaxValue as default estimate" src="https://davidelettieri.it/img/best_arm_selection_rate_max_value.png"><figcaption>The best arm selection rate per step, per strategy using double.MaxValue as default estimate</figcaption></figure>]]></content:encoded>
            <category>c#</category>
            <category>reinforcement-learning</category>
            <category>k-armed bandit problem</category>
        </item>
        <item>
            <title><![CDATA[CSV parsing with typescript]]></title>
            <link>https://davidelettieri.it/2025/04/10/csv-parsing-with-typescript</link>
            <guid>https://davidelettieri.it/2025/04/10/csv-parsing-with-typescript</guid>
            <pubDate>Thu, 10 Apr 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A few years ago I needed to troubleshoot some imports based on csv files and I had one big issue, depending on the language the user was using on Windows, Excel would export csv files with different separators. Being located in Italy, this means that the separator was ;. The same was true when trying to read csv with Excel, the separator is chosed based on the language of the OS.]]></description>
            <content:encoded><![CDATA[<p>A few years ago I needed to troubleshoot some imports based on csv files and I had one big issue, depending on the language the user was using on Windows, Excel would export csv files with different separators. Being located in Italy, this means that the separator was <code>;</code>. The same was true when trying to read csv with Excel, the separator is chosed based on the language of the OS.</p>
<p>I prefer to set up everything in English because I think it is easier to troubleshoot issues when the error is not localized to Italian.</p>
<p>So I couldn't read csv just opening them on Excel because of the separator, Excel also formats field depending on the content. It might hide leading zeros if it thinks a column is filled with numbers, dates are problematic and so on. I wanted to be able to see the actual content of the csv in a tabular format without fighting with Excel for the separator or for automatic formatting of columns.</p>
<p>I decided to go ahead and build a simple parser, hostable on a website that would read a csv and just print the values without any custom formatting and with the possibility to choose the separator. Of course today I would go with a vs code extension, I'm sure there are plenty doing something similar better than I did in a few hours but at the time this small parser was enough to support my need.</p>
<p>CSV is not a well defined or well agreed format, however there is a <a href="https://datatracker.ietf.org/doc/html/rfc4180" target="_blank" rel="noopener noreferrer" class="">IEFT RFC </a> that documents the format. Following that I implemented a parser in typescript that read a csv and creates an html table with the content manipulating the DOM directly.</p>
<p>The repo is this one: <a href="https://github.com/davidelettieri/yacv" target="_blank" rel="noopener noreferrer" class="">https://github.com/davidelettieri/yacv</a></p>
<p>Online demo: <a href="https://davidelettieri.github.io/yacv/" target="_blank" rel="noopener noreferrer" class="">https://davidelettieri.github.io/yacv/</a></p>
<p>Just today I revisited the code, adding some basic tests and updating typescript version.</p>]]></content:encoded>
            <category>typescript</category>
            <category>csv</category>
            <category>parsers</category>
        </item>
        <item>
            <title><![CDATA[Asynchronous request reply pattern without polling]]></title>
            <link>https://davidelettieri.it/2025/04/02/asynchronous-request-reply-pattern</link>
            <guid>https://davidelettieri.it/2025/04/02/asynchronous-request-reply-pattern</guid>
            <pubDate>Fri, 04 Apr 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[The asynchronous request reply pattern is useful in cases where an application has a client application running in a browser where the user starts an operation and is waiting for an immediate feedback and possibly a success notification. An issue arises only if the requested operation is long running, even a few seconds is unacceptable to return a feedback to a waiting user. Microsoft has a nice documentation about this pattern which essentially propose to have 3 endpoints:]]></description>
            <content:encoded><![CDATA[<p>The asynchronous request reply pattern is useful in cases where an application has a client application running in a browser where the user starts an operation and is waiting for an immediate feedback and possibly a success notification. An issue arises only if the requested operation is long running, even a few seconds is unacceptable to return a feedback to a waiting user. <a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/async-request-reply" target="_blank" rel="noopener noreferrer" class="">Microsoft has a nice documentation about this pattern</a> which essentially propose to have 3 endpoints:</p>
<ul>
<li class="">a POST endpoint to start the long running operation: <code>POST /operations</code></li>
<li class="">a GET endpoint to check for the status of the operation <code>GET /operations/{id}/status</code></li>
<li class="">a GET endpoint pointing to the created resource <code>GET /operations/{id}</code></li>
</ul>
<p>The actual path for the endpoints might vary and aren't explicitely provided in the Microsoft docs, I'm proposing those for the sake of the post, based on your requirements and the semantic of your API you might want have different ones. The interaction flow between the client and the backend is this one:</p>
<!-- -->
<p>For example the <code>POST /operations</code> can return something like</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"id"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"links"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"rel"</span><span class="token operator" style="color:#393A34">:</span><span class="token string" style="color:#e3116c">"status_check"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"href"</span><span class="token operator" style="color:#393A34">:</span><span class="token string" style="color:#e3116c">"https://api.contoso.com/operations/1/status"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"action"</span><span class="token operator" style="color:#393A34">:</span><span class="token string" style="color:#e3116c">"GET"</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>This flow allows the backend to perform the asynchronous/long running operation and any client can poll the status endpoint and notify the user when the operation is completed. The big advantage of this setup is that it is easy to implement, for example websockets could be an option but they are usually harder to use and you will probably need a third party library to use them. A downside of the polling approach is that a client can execute a lot of retries in a short amount of time, Microsoft suggests to provide a <code>Retry-After</code> header that the client <strong>should</strong> honor and wait for the indicated time, if you own the client this is an easy requirement to satisfy. While this pattern has a clear use case with browser based clients, for a machine to machine integration I would prefer implementing webhooks bot as a producer and as a consumer. However a company with a low tech maturity / capacity can implementing the polling approach very easily.</p>
<p>In my opinion there is another approach to this pattern, for a browser client, that avoids having the polling on the endpoint and doesn't require websockets. If you have a dedicated <a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/backends-for-frontends" target="_blank" rel="noopener noreferrer" class="">BFF</a> for a client app this might be the solution for you.</p>
<p>My proposal is based on 3 endpoints, like the Microsoft one, however the status endpoint is using Server-sent events to notify the frontend about the completion of the long running operation. At the time of writing <a href="https://caniuse.com/eventsource" target="_blank" rel="noopener noreferrer" class="">caniuse.com shows a 96.94% support</a> across browser and notes:</p>
<blockquote>
<p>Since January 2020, this feature works across the latest devices and major browser versions</p>
</blockquote>
<p>So the Server-sent event feature is supported enough to be used, of course less supported than http requests, however it is a viable options if we want to avoid polling and other more complex solutions like websockets. Before choosing this path, some other limitations need to be taken into account, for example the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events" target="_blank" rel="noopener noreferrer" class="">mdn web docs show this warning </a></p>
<blockquote>
<p>Warning: When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections, which can be especially painful when opening multiple tabs, as the limit is per browser and is set to a very low number (6). The issue has been marked as "Won't fix" in Chrome and Firefox. This limit is per browser + domain, which means that you can open 6 SSE connections across all of the tabs to <a href="http://www.example1.com/" target="_blank" rel="noopener noreferrer" class="">www.example1.com</a> and another 6 SSE connections to <a href="http://www.example2.com/" target="_blank" rel="noopener noreferrer" class="">www.example2.com</a> (per Stack Overflow). When using HTTP/2, the maximum number of simultaneous HTTP streams is negotiated between the server and the client (defaults to 100).</p>
</blockquote>
<p>That said, ChatGPT UI is using server events to get the responses for the backend, just look at the network panel of the browser to see how it works.</p>
<figure><img style="margin:0 auto;display:block" alt="the network panel of the browser showing the conversation request" src="https://davidelettieri.it/img/open-ai-server-events.png"><figcaption>The network panel of the browser showing the conversation request</figcaption></figure>
<figure><img style="margin:0 auto;display:block" alt="The event stream detail of the request" src="https://davidelettieri.it/img/open-ai-server-events-2.png"><figcaption>The event stream detail of the request</figcaption></figure>
<p>If server-sent events are enough for ChatGPT they might be enough even for us. How do we use them to implement the asynchronous request reply pattern? We change the payload returned by the <code>POST /operations</code> to</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"id"</span><span class="token operator" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"links"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"rel"</span><span class="token operator" style="color:#393A34">:</span><span class="token string" style="color:#e3116c">"status_check"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"href"</span><span class="token operator" style="color:#393A34">:</span><span class="token string" style="color:#e3116c">"https://api.contoso.com/operations/1/status"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"action"</span><span class="token operator" style="color:#393A34">:</span><span class="token string" style="color:#e3116c">"EventSource"</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Almost the same as before, the <code>action</code> is now <code>EventSource</code> so that the client knowns what to do with the endpoint, this value is not standard (as far as I known) choose and document whatever makes sense for you and your team. On the frontend, instead of the polling code, what we have to do is this:</p>
<div class="language-javascript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-javascript codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> evtSource </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">EventSource</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"https://api.contoso.com/operations/1/status"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">evtSource</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pending"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// handle pending</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">evtSource</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"completed"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// handle completed, shows notification/toast</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// close the connection</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    evtSource</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">close</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">evtSource</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"error"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// handle completed, shows notification/toast</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic">// close the connection</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    evtSource</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">close</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre></div></div>
<p>I added samples for multiple events, at very least we need one to notify the completion of the operation. Since events can carry information in the <code>event.data</code> field the resource URI can be returned in the completed event payload. With this approach the interaction flow is the following:</p>
<!-- -->
<p>I prepared a sample C# project with a simple html + javascript UI that shows a simple implementation of the three endpoints and how the frontend is receiving the updates and closing the connection when completed. The asynchronous work is represented by a Task that just waits before completing. The code is on <a href="https://github.com/davidelettieri/asynchronous-request-reply-pattern" target="_blank" rel="noopener noreferrer" class="">github</a>.</p>]]></content:encoded>
            <category>c#</category>
            <category>cloud-design-patterns</category>
        </item>
        <item>
            <title><![CDATA[Tic-tac-toe reinforcement learning with C#]]></title>
            <link>https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp</link>
            <guid>https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp</guid>
            <pubDate>Sun, 16 Mar 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A couple of weeks ago I wanted to take a look at reinforcement learning and possibly work on a very simple sample in C#. In search for a book to learn some basics I found Reinforcement Learning: An Introduction suggested in multiple places. The book is available for free as a PDF on the linked website, so I thought it would be a good starting point.]]></description>
            <content:encoded><![CDATA[<p>A couple of weeks ago I wanted to take a look at reinforcement learning and possibly work on a very simple sample in C#. In search for a book to learn some basics I found <a href="http://incompleteideas.net/book/the-book-2nd.html" target="_blank" rel="noopener noreferrer" class=""><strong>Reinforcement Learning: An Introduction</strong></a> suggested in multiple places. The book is available for free as a PDF on the linked website, so I thought it would be a good starting point.</p>
<p>The book offers in the very first chapter, a tic-tac-toe example where an algorithm is described, albeit with not too much details. I decided to try to implement a C# version of that. Plenty of implementations are available online and the authors offer a <code>lisp</code> version on their website, so there is a wide range of option to explore and evaluate.</p>
<p>I will report part of the text of the example here to comment on it and provide some additional details that I think would helped me in understanding the example. In short the objective of the exercise is to implement a player, <code>QPlayer</code> in my case, that plays the <code>X</code> symbol and decides what move to play based on a function that assigns a value to each state of the game. This value function will be improved iteratively by making the <code>QPlayer</code> play against another automated player. The state of the game is a possible configuration of <code>X</code> and <code>O</code> on the 3x3 grid. The value function is a function that assigns a double value to each state of the game.</p>
<p>From the book:</p>
<blockquote>
<p>Here is how the tic-tac-toe problem would be approached with a method
making use of a value function. First we set up a table of numbers, one for
each possible state of the game. Each number will be the latest estimate of
the probability of our winning from that state. We treat this estimate as the
state’s value, and the whole table is the learned value function. State A has
higher value than state B, or is considered “better” than state B, if the current
estimate of the probability of our winning from A is higher than it is from B.
Assuming we always play Xs, then for all states with three Xs in a row the
probability of winning is 1, because we have already won. Similarly, for all
states with three Os in a row, or that are “filled up,” the correct probability
is 0, as we cannot win from them. We set the initial values of all the other
states to 0.5, representing a guess that we have a 50% chance of winning.
We play many games against the opponent. To select our moves we examine
the states that would result from each of our possible moves (one for each blank
space on the board) and look up their current values in the table. Most of the
time we move greedily, selecting the move that leads to the state with greatest
value, that is, with the highest estimated probability of winning. Occasionally,
however, we select randomly from among the other moves instead. These are
called exploratory moves because they cause us to experience states that we
might otherwise never see.
While we are playing, we change the values of the states in which we find
ourselves during the game. We attempt to make them more accurate estimates
of the probabilities of winning. To do this, we “back up” the value of the state
after each greedy move to the state before the move [...]. More precisely, the current value of the earlier state is adjusted
to be closer to the value of the later state. This can be done by moving the
earlier state’s value a fraction of the way toward the value of the later state.
If we let s denote the state before the greedy move, and s' the state after
the move, then the update to the estimated value of s, denoted V (s), can be
written as
V(s) = V(s) + α [V(s') − V(s)],
where α is a small positive fraction called the step-size parameter, which influences the rate of learning. This update rule is an example of a temporal-difference learning method, so called because its changes are based on a difference, V(s') − V(s), between estimates at two different times.</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="move-selection-and-backup-from-the-book">Move selection and backup from the book<a href="https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp#move-selection-and-backup-from-the-book" class="hash-link" aria-label="Direct link to Move selection and backup from the book" title="Direct link to Move selection and backup from the book" translate="no">​</a></h2>
<p>Blocks represent state of the game. Arrows represent moves taken by either player.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="comments-on-the-example">Comments on the example<a href="https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp#comments-on-the-example" class="hash-link" aria-label="Direct link to Comments on the example" title="Direct link to Comments on the example" translate="no">​</a></h2>
<p>Given the book description of the algorithm we need to build a value function <code>V</code> that can change at execution time, as our player learns more about the game. To do this we implement the value function as a dictionary lookup. We gave initial values for all states as described by the text above:</p>
<ul>
<li class="">value 1: winning position for learning player.</li>
<li class="">value 0: losing position for learning player.</li>
<li class="">value 0.5: all other positions.</li>
</ul>
<p>The first observation to be made is that the value table is depending on the player we are training because of course changing the player from <code>X</code> to <code>O</code> will switch winning and losing positions, switching by consequence the values of those positions.</p>
<p>Second point is that, while we give each position a value following a general rule, the state space can be divided into two disjoint sets:</p>
<ul>
<li class="">the set of states that can be updated and used by the algorithm (but will not be updated necessarily, there is a bit of randomization at play)</li>
<li class="">the set of states that will never be updated or used by the algorithm</li>
</ul>
<p>Again this two sets are fixed once we fix the player we want to train, in our case <code>X</code>. Let's think about the update rule <code>V(s) = V(s) + α [V(s') − V(s)]</code>, we have two states <code>s</code> and <code>s'</code>, in both states, <code>X</code> has just moved. This means that the number of <code>X</code> and <code>O</code> on the 3x3 grid are not equal because <code>X</code> always moves first and so we have one <code>X</code> more than <code>O</code>. So we already understand that states with equal number of <code>X</code> and <code>O</code> will never be updated. Also when we evaluate next positions to choose the best move to make, we evaluate all position where <code>X</code> has moved so again we only use states where <code>X</code> and <code>O</code> have the same amount of positions on the grid. This point is not really important, unless you want to observe the value function changing over time and you notice some values to never be updated.</p>
<p>While realizing this, I was wondering also: if we learn only when <code>X</code> moves, why do have the value function for state where <code>X</code> lose? We will never reach a losing state for <code>X</code> from a <code>X</code> move and a losing state for <code>X</code> is a grid with equal amount of <code>X</code> and <code>O</code>. Right? In my opinion that is not correct, so I amended the algorithm to learn from each non-random move of <code>X</code> and to learn, or "back-up" as the text put it, even when the <code>X</code> player is losing after a move from <code>O</code>. This change will allow us to use the zero valued states from the value function.</p>
<p>So after this considerations and my proposed change for the "back-up" algorithm, we know that the only states used in learning are the states where <code>X</code> has moved or <code>X</code> lose. All the other states won't impact the learning process. If we train the <code>O</code> player the sets of course change accordingly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="proposed-move-selection-and-backup">Proposed move selection and backup<a href="https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp#proposed-move-selection-and-backup" class="hash-link" aria-label="Direct link to Proposed move selection and backup" title="Direct link to Proposed move selection and backup" translate="no">​</a></h2>
<p>Blocks represent state of the game. Arrows represent moves taken by either player. With respect to the original approach, we only add a final back-up if the ending position is losing position for our player.</p>
<!-- -->
<p>An additional observation is that during training time, the <code>O</code> player is implemented as the <code>X</code> player only with more probability of choosing a random move, according to the text the <code>O</code> player should play randomly, with my implementation this means passing <code>1</code> as exploration rate in the <code>QPlayer</code> constructor when instantiating the <code>O</code> player. My code can be found <a href="https://github.com/davidelettieri/sutton-barto-reinforcement-learning" target="_blank" rel="noopener noreferrer" class="">on github</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="exercise-11-about-the-tic-tac-toe-example">Exercise 1.1 about the tic-tac-toe example<a href="https://davidelettieri.it/2025/03/16/tic-tac-toe-reinforcement-learning-with-c-sharp#exercise-11-about-the-tic-tac-toe-example" class="hash-link" aria-label="Direct link to Exercise 1.1 about the tic-tac-toe example" title="Direct link to Exercise 1.1 about the tic-tac-toe example" translate="no">​</a></h2>
<p>Last point is that I'm a bit confused about the first exercise of the Chapter:</p>
<blockquote>
<p>Exercise 1.1: Self-Play Suppose, instead of playing against a random
opponent, the reinforcement learning algorithm described above played against
itself. What do you think would happen in this case? Would it learn a different
way of playing?</p>
</blockquote>
<p>I think there might be two different interpretations of this exercise:</p>
<ol>
<li class="">We make the reinforcement learning player play against itself, interpreted as the same <strong>instance</strong> of the player. In this case we are saying that we are going to play both <code>X</code> and <code>O</code> on a value function built for <code>X</code> winning. Should me make the instance learn or back-up values of both moves? I feel like this doesn't make much sense.</li>
<li class="">We make two different instances of our reinforcement learning player with appropriate value functions for <code>X</code> and <code>O</code> and we make them play against each other. This is what I implemented, the <code>QPlayer</code> class accepts a parameter <code>explorationRate</code> that controls the randomization of the instance, with <code>1</code> it is fully random and it won't learn anything, with <code>0</code> it always choose the best move based on the value function (but no exploratory moves!). I played a bit with the randomization of the <code>O</code> player and I didn't notice much differences on the outcomes.</li>
</ol>]]></content:encoded>
            <category>c#</category>
            <category>reinforcement-learning</category>
        </item>
        <item>
            <title><![CDATA[Kaleidoscope tutorial with C# using LLVMSharp and llvm 18]]></title>
            <link>https://davidelettieri.it/2025/02/15/kaleidoscope-tutorial-llvmsharp-18</link>
            <guid>https://davidelettieri.it/2025/02/15/kaleidoscope-tutorial-llvmsharp-18</guid>
            <pubDate>Thu, 20 Feb 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Since writing this, LLVMSharp had a new stable v20 release. The code in the repo is updated to this package.]]></description>
            <content:encoded><![CDATA[<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Since writing this, LLVMSharp had a new stable v20 release. The code in the repo is updated to this package.</p></div></div>
<p>A few years ago I worked on reproducing the Kaleidoscope tutorial using LLVMSharp, a library that exposes C# bindings for LLVM. I updated multiple times the project to support the latest versions of llvm and the LLVMSharp bindings. In the last week I was busy moving to llvm 18 and I encountered a few difficulties.</p>
<p>First, the newest version of LLVMSharp available on nuget is <code>16.0.0</code>, however the <a href="https://github.com/dotnet/LLVMSharp" target="_blank" rel="noopener noreferrer" class="">corresponding repo</a> is updated to support version <code>18.0.0</code> of llvm. Luckily for me, there is a nighly nuget feed where a release candidate of LLVMSharp supporting version <code>18.0.0</code> is available. Please note that at the time of writing the latest llvm version is <code>19</code>, LLVMSharp is updated inconsistently and it has been since the beginning for what I could see.</p>
<p>Now, once I decided to go with llvm <code>18</code> and found the right source for the package, the next big issue was the removal of the <code>PassManagerBuilder.h</code> starting from version <code>17.0.0</code> as detailed in the <a href="https://releases.llvm.org/17.0.1/docs/ReleaseNotes.html#changes-to-llvm-infrastructure" target="_blank" rel="noopener noreferrer" class="">release notes</a>. There is a documentation on how to use the new pass manager <a href="https://llvm.org/docs/NewPassManager.html" target="_blank" rel="noopener noreferrer" class="">here</a> using <code>C++</code> but LLVMSharp is exposing the <code>C</code> api of llvm. There is a point were <code>C</code> apis are mentioned in the new docs</p>
<blockquote>
<p>The C API also supports most of this, see llvm-c/Transforms/PassBuilder.h.</p>
</blockquote>
<p>Given that:</p>
<ol>
<li class="">I'm not an expert on llvm</li>
<li class="">I'm not an expert on <code>C</code> nor <code>C++</code></li>
</ol>
<p>It wasn't obvious to me how to use the new pass manager. I did quite some research on internet and on github trying to find samples and how-tos, with little luck tbh.</p>
<p>One source that I think is good quality but overall too complex for me was the source code for the <code>C3</code> language, they are using the <code>C</code> api of llvm and indeed using the new PassBuilder. However while the compiler is written in <code>C</code> using the <code>C</code> apis of llvm, the bit about the pass manager has a <a href="https://github.com/c3lang/c3c/blob/79db06ecd142065d62766500735dd85deed0fbf3/wrapper/src/wrapper.cpp" target="_blank" rel="noopener noreferrer" class=""><code>C++</code> wrapper</a>. So I'm out of luck on this.</p>
<p>Finally, I found a working approach in the place were I should have looked first (but didn't!), the llvm project itself. <a href="https://github.com/llvm/llvm-project/blob/3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff/llvm/unittests/Passes/PassBuilderBindings/PassBuilderBindingsTest.cpp" target="_blank" rel="noopener noreferrer" class="">They have unit tests for the new PassManager</a>, with that it was easy to get something working.</p>
<p>The approach that I'm following now with llvm 18 is not exactly the same as the one with llvm 16, because before I had a function pass manager and I was applying the passes on each single function, now I'm applying the passes to the whole module. I don't know what's the status now (at version <code>19.0.x</code> of llvm) and I don't know if it was possible to keep the old approach but I wasn't able to do it. For my scope, it is enough what I have now.</p>
<p>The passes need to be passed as a comma separated string to the <code>LLVMRunPasses</code> function, <a href="https://llvm.org/docs/Passes.html" target="_blank" rel="noopener noreferrer" class="">here</a> the list of the current available passes. The code using llvm <code>16</code> was having both analysis passes and transform passes for no other reason that I was mimicking what was done in the original Kaleidoscope tutorial.</p>
<p>The <code>LLVMRunPasses</code> didn't accept the only analysis pass I had, <code>basic-aa</code>, but accepted all the transforms. This is somehow understandable as the pass manager comes from <code>llvm-c/Transforms/PassBuilder.h</code>. I guess for analysis passes there is another infrastructure.</p>
<p>Now my <a href="https://github.com/davidelettieri/kaleidoscope/" target="_blank" rel="noopener noreferrer" class="">kaleidoscope repo</a> is updated and functional, still able to run the mandelbrot example.</p>]]></content:encoded>
            <category>c#</category>
            <category>llvm</category>
            <category>kaleidoscope</category>
        </item>
        <item>
            <title><![CDATA[Trying to implement Lox as Racket language module]]></title>
            <link>https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module</link>
            <guid>https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module</guid>
            <pubDate>Sat, 18 Jan 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Given my previous attempt of having a basic scaffolding for creating a new racket language, I thought it was worth a shot at implementing Lox from the Crafting interpreters book as a Racket language module.]]></description>
            <content:encoded><![CDATA[<p>Given my previous attempt of having a basic scaffolding for <a class="" href="https://davidelettieri.it/2023/02/25/Creating-a-new-racket-language">creating a new racket language</a>, I thought it was worth a shot at implementing Lox from the <a href="https://craftinginterpreters.com/" target="_blank" rel="noopener noreferrer" class="">Crafting interpreters book</a> as a Racket language module.</p>
<p>Racket has a huge ecosystem and extensive documentation, based on my own research and preferences I decided to use a lex/yacc source generator available in Racket itself and documented here <a href="https://docs.racket-lang.org/lex-yacc-example/index.html" target="_blank" rel="noopener noreferrer" class="">https://docs.racket-lang.org/lex-yacc-example/index.html</a>. There are plenty of resources on how to build languages with Racket, both free and paid.</p>
<p>I used only free resources and my feeling is that the amount of information required to approach this project is A LOT, I needed to get familiar with lisp syntax, libraries for parsing, macros, Racket language modules, a different set of tools for coding/debugging.</p>
<p>Another feeling I have is that the documentation, even if it's extensive, it's not providing all the information required to build new languages for Racket or at very least this information is hard to find. I didn't find it, despite trying multiple times.</p>
<p>All of this to anticipate that I failed and I failed for multiple reasons:</p>
<ol>
<li class="">Lack of continuity on the project: I couldn't work on this with the energy I would have needed to succeed in this.</li>
<li class="">Lack of (or difficulty in finding) proper documentation for Racket languages. I will add some links later on what I found most useful.</li>
<li class="">Possible wrong/unoptimal choices: for example I tried to use the test infrastructure provided in the <a href="https://github.com/munificent/craftinginterpreters/" target="_blank" rel="noopener noreferrer" class="">craftinginterpreters</a> repo. This required having exit codes and writing to stderr, even if this seems simple, trying to make this work with Linux, Windows and DrRacket (the IDE provided with Racket) was a problem I couldn't solve.</li>
</ol>
<p>I kept the repo private for a long time, while trying to work on it and hoping to have it completed and polished, however that time might never come so now the <a href="https://github.com/davidelettieri/racket-lox" target="_blank" rel="noopener noreferrer" class="">repository is public</a>. I didn't invest time in documenting how to run things because it's a failed project so I don't feel doing it.</p>
<p>However, all the tests from chapter 8 of the book pass, so if you clone the repo, move to the cloned folder and run <code>raco pkg install</code> then you can open a racket file and execute this.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">#lang racket-lox</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var a = "a";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var b = "b";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">var c = "c";</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">// Assignment is right-associative.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">a = b = c;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">print a; // expect: c</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">print b; // expect: c</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">print c; // expect: c</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-could-have-i-done-differently">What could have I done differently?<a href="https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module#what-could-have-i-done-differently" class="hash-link" aria-label="Direct link to What could have I done differently?" title="Direct link to What could have I done differently?" translate="no">​</a></h2>
<p>I guess ditch the whole lex/yacc parser tools and implement a manual tokenizer and parser as it is done in the book itself. Doing this will remove complexity around the parser and might give more explicit control on the code.</p>
<p>Another point could be not using macros. Macros are cool, they are powerful and somehow they are a key advantage in lisps languages (if you can use them), I decided to use them to try to feel what it means to have this powerful compile time construct, as a .NET developer this is quite new, maybe source generators can play a similar role but with the same developer experience. What's certain about macros is that they add complexity to the code and it is one more thing to understand and control.</p>
<p>Do not use the test infrastructure provided by the author of the book. That infrastructure is good and useful and I used it when building <a href="https://github.com/davidelettieri/Lox" target="_blank" rel="noopener noreferrer" class="">my c# implementation</a> which was more aligned in intent with the Java version of the book: building an interpreter. Given that a Racket language module is a different beast, I feel like this decision costed me more time that it saved.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="did-i-learn-something-useful">Did I learn something useful?<a href="https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module#did-i-learn-something-useful" class="hash-link" aria-label="Direct link to Did I learn something useful?" title="Direct link to Did I learn something useful?" translate="no">​</a></h2>
<p>I learned a bit the lex/yacc parser tools, I don't feel this was useful. It was painful enough for me to not want to have anything to do with this again.</p>
<p>I learned a bit of Racket macros and how to troubleshoot them with the <code>Macro Stepper</code> function of DrRacket, this was a useful bit and if I continue playing with Racket I will definitively use it again.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="most-useful-resource">Most useful resource?<a href="https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module#most-useful-resource" class="hash-link" aria-label="Direct link to Most useful resource?" title="Direct link to Most useful resource?" translate="no">​</a></h2>
<p>The <strong>Racket School 2019: The “How to Design Languages” Track</strong> website <a href="https://school.racket-lang.org/2019/plan/" target="_blank" rel="noopener noreferrer" class="">https://school.racket-lang.org/2019/plan/</a>. This is a nice, complex, rather comprehensive documentation on building languages and on implicit forms like <code>#%module-begin</code> and <code>#%app</code> and all the others. I didn't even arrive at the typing part and it was still useful.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="second-best">Second best?<a href="https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module#second-best" class="hash-link" aria-label="Direct link to Second best?" title="Direct link to Second best?" translate="no">​</a></h3>
<p>An implementation of brainf**k language as a Racket language module <a href="https://www.hashcollision.org/brainfudge/" target="_blank" rel="noopener noreferrer" class="">https://www.hashcollision.org/brainfudge/</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="closing-thoughts">Closing thoughts<a href="https://davidelettieri.it/2025/01/18/trying-to-implement-lox-as-racket-language-module#closing-thoughts" class="hash-link" aria-label="Direct link to Closing thoughts" title="Direct link to Closing thoughts" translate="no">​</a></h2>
<p>Not much to be honest, I would suggest any novice on Racket like me to avoid the parser tools library. It's hard and not much documented. Racket looks like a very powerful tool but it's language building capabilities are not documented enough to make it available to a wide audience. At least those are my feelings.</p>
<p>The only path I see to move forward is to rewrite the project and mimic as much as possible the parser from the book, it's a recursive descent parser, it's easy and readable. Use mutability, even if Racket is a functional language, and move from there.</p>
<p>I'll be happy for any comment on the code, or for additional useful resources anyone might have on the topic.</p>]]></content:encoded>
            <category>racket</category>
            <category>lox</category>
            <category>lisp</category>
        </item>
        <item>
            <title><![CDATA[Fedora, switch audio channels with pipewire and wireplumber 0.5]]></title>
            <link>https://davidelettieri.it/2024/06/21/fedora-pipewire-switch-channels-wireplumber-0.5</link>
            <guid>https://davidelettieri.it/2024/06/21/fedora-pipewire-switch-channels-wireplumber-0.5</guid>
            <pubDate>Fri, 21 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This is an update on this post, on wireplumber v0.5 lua configuration files are not supported anymore. To switch channels on v0.5 you have to create the following file]]></description>
            <content:encoded><![CDATA[<p>This is an update on <a class="" href="https://davidelettieri.it/2024/02/04/fedora-pipewire-switch-channels">this post</a>, on wireplumber v0.5 lua configuration files are not supported anymore. To switch channels on v0.5 you have to create the following file</p>
<div class="language-spa codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">.config/wireplumber/wireplumber.conf.d/51-change-channels.conf</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-spa codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">monitor.alsa.rules = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    matches = [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        node.name = "&lt;name of the node&gt;"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    actions = {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      update-props = {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        audio.position = "FR,FL"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">]</span><br></span></code></pre></div></div>
<p>Check the previous post to understand how to retrieve the name of the node, if needed.</p>]]></content:encoded>
            <category>linux</category>
            <category>fedora</category>
            <category>pipewire</category>
            <category>wireplumber</category>
        </item>
        <item>
            <title><![CDATA[Use cilium service mesh on AKS]]></title>
            <link>https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh</link>
            <guid>https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh</guid>
            <pubDate>Thu, 21 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[On 2025-08-02 I updated the repo corresponding to this post to use updated versions of Kubernetes, Cilium and Gateway API. The post is not updated accordingly. I did follow again the procedure explained here to confirm that everything is still working as expected. Most notable change is that we don't need experimental channel of Gateway API except for one resource, as described in Cilium v1.17.0 docs.]]></description>
            <content:encoded><![CDATA[<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_BuS1"><p>On 2025-08-02 I updated the repo corresponding to this post to use updated versions of Kubernetes, Cilium and Gateway API. The post is not updated accordingly. I did follow again the procedure explained here to confirm that everything is still working as expected. Most notable change is that we don't need experimental channel of Gateway API except for one resource, as described in Cilium v1.17.0 docs.</p></div></div>
<p>Azure BYOCNI configuration allows the use of <a href="https://cilium.io/" target="_blank" rel="noopener noreferrer" class="">cilium</a> as CNI, in addition to that it is possible to configure <a href="https://docs.cilium.io/en/stable/network/servicemesh/#servicemesh-root" target="_blank" rel="noopener noreferrer" class="">cilium service mesh</a>.</p>
<p>Cilium service mesh has several functionalities such as ingress controller, gateway api, mtls etc... my objective here is to use <a href="https://gateway-api.sigs.k8s.io/" target="_blank" rel="noopener noreferrer" class="">k8s gateway api</a>. In order to enable cilium service mesh we have to replace kube-proxy with cilium itself, to do so we need to enable the kube proxy configuration feature on aks, which is currently in preview.</p>
<p>Cilium supports gateway api v1 from version 1.15, which is the one that I'm installing today. In particular I will install gateway api v1 experimental channel. This will allow to configure the underlying infrastructure (an azure load balancer) if needed.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-repo">The repo<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#the-repo" class="hash-link" aria-label="Direct link to The repo" title="Direct link to The repo" translate="no">​</a></h2>
<p><a href="https://github.com/davidelettieri/aks-cilium-service-mesh" target="_blank" rel="noopener noreferrer" class="">This github repo</a> contains the bicep files I used to deploy and all the commands required to perform the full installation. I will go through the different steps.</p>
<p>The repo contains a devcontainer definition, which has:</p>
<ul>
<li class="">kubectl</li>
<li class="">az cli</li>
<li class="">cilium cli</li>
<li class="">bicep and bicep vs code extension</li>
</ul>
<p>Please login with <code>az</code> before performing any step.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="enable-preview-feature">Enable preview feature<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#enable-preview-feature" class="hash-link" aria-label="Direct link to Enable preview feature" title="Direct link to Enable preview feature" translate="no">​</a></h2>
<p>We need to enable <a href="https://learn.microsoft.com/en-us/azure/aks/configure-kube-proxy" target="_blank" rel="noopener noreferrer" class="">kube proxy configuration</a>. This step requires some time, I suggest to do this at the beginning and while we wait we can proceed with infrastructure deployment.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Install preview kube proxy configuration feature</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az feature register </span><span class="token parameter variable" style="color:#36acaa">--namespace</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Microsoft.ContainerService"</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"KubeProxyConfigurationPreview"</span><br></span></code></pre></div></div>
<p>To check progress on this run</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Check feature registration status</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az feature show </span><span class="token parameter variable" style="color:#36acaa">--namespace</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Microsoft.ContainerService"</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"KubeProxyConfigurationPreview"</span><br></span></code></pre></div></div>
<p>What do want to see is</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Feature is registered</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">"id"</span><span class="token builtin class-name">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/subscriptions/&lt;subscription-id&gt;/providers/Microsoft.Features/providers/Microsoft.ContainerService/features/KubeProxyConfigurationPreview"</span><span class="token plain">,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">"name"</span><span class="token builtin class-name">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Microsoft.ContainerService/KubeProxyConfigurationPreview"</span><span class="token plain">,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">"properties"</span><span class="token builtin class-name">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"state"</span><span class="token builtin class-name">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Registered"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain">,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">"type"</span><span class="token builtin class-name">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Microsoft.Features/providers/features"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="infrastructure-deployment">Infrastructure deployment<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#infrastructure-deployment" class="hash-link" aria-label="Direct link to Infrastructure deployment" title="Direct link to Infrastructure deployment" translate="no">​</a></h2>
<p>We need to deploy 2 resources, the resource group and the AKS cluster. The AKS cluster will create an additional resource group and some resources inside that. This is expected and it's not related to the kind of deployment we are doing. We could, if needed, create some of the required resources instead of letting all of them be managed by AKS. One example is the vnet, we could deploy a vnet before deploying AKS and then have the cluster inside that vnet. That would give us much greater control, we could add a firewall, a NAT gateway, decide CIDR for nodes and pods, etc... This is a supported scenario and it could be necessary to do so based on cluster requirements.</p>
<p>I'm deploying the minimum amount of resources needed to have cilium service mesh working, which is a resource group and an aks cluster. The cluster itself will manage the underlying network.</p>
<p>In the repo a parameter file is provided with some default option, you can tweak some names and the sku of the vm and the load balancer. My objective here is to keep cost at a minimum. I wouldn't suggest to use those values for a production deployment.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Deploy AKS</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az deployment sub create </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> aks-cilium-service-mesh </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    --template-file bicep/main.bicep </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token parameter variable" style="color:#36acaa">--parameters</span><span class="token plain"> bicep/main.bicepparam </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token parameter variable" style="color:#36acaa">--location</span><span class="token plain"> westeurope</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az aks get-credentials --resource-group </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$rgName</span><span class="token string" style="color:#e3116c">"</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$aksName</span><span class="token string" style="color:#e3116c">"</span><br></span></code></pre></div></div>
<p>The last line in the sample will create a context for kubectl so that we can access the cluster later on.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="disable-kube-proxy">Disable kube proxy<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#disable-kube-proxy" class="hash-link" aria-label="Direct link to Disable kube proxy" title="Direct link to Disable kube proxy" translate="no">​</a></h2>
<p>Verify that the feature has been registered</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Check feature registration status</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az feature show </span><span class="token parameter variable" style="color:#36acaa">--namespace</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Microsoft.ContainerService"</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--name</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"KubeProxyConfigurationPreview"</span><br></span></code></pre></div></div>
<p>If so proceed with</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Disable kube proxy</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az provider register </span><span class="token parameter variable" style="color:#36acaa">--namespace</span><span class="token plain"> Microsoft.ContainerService</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">az aks update </span><span class="token parameter variable" style="color:#36acaa">-g</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$rgName</span><span class="token string" style="color:#e3116c">"</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-n</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$aksName</span><span class="token string" style="color:#e3116c">"</span><span class="token plain"> --kube-proxy-config kube-proxy.json</span><br></span></code></pre></div></div>
<p>The configuration file is quite simple:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">kube-proxy.json</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"enabled"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-gateway-api">Install gateway api<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#install-gateway-api" class="hash-link" aria-label="Direct link to Install gateway api" title="Direct link to Install gateway api" translate="no">​</a></h2>
<p>We need to install the custom resources of gateway api <strong>before</strong> installing cilium. We want the experimental channel in order to have the <a href="https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.GatewayInfrastructure" target="_blank" rel="noopener noreferrer" class=""><code>infrastructure</code> field</a> in the Gateway definition. This will allow us to use azure annotations to configure the load balancer.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Install gateway api with kubectl</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">kubectl apply </span><span class="token parameter variable" style="color:#36acaa">-f</span><span class="token plain"> https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/experimental-install.yaml</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-cilium">Install cilium<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#install-cilium" class="hash-link" aria-label="Direct link to Install cilium" title="Direct link to Install cilium" translate="no">​</a></h2>
<p>Now we are ready to install cilium with the required options to enable service mesh functionality</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">cilium </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--version</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.15</span><span class="token plain">.2 </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token parameter variable" style="color:#36acaa">--set</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">azure.resourceGroup</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$rgName</span><span class="token string" style="color:#e3116c">"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token parameter variable" style="color:#36acaa">--set</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">kubeProxyReplacement</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">true </span><span class="token punctuation" style="color:#393A34">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token parameter variable" style="color:#36acaa">--set</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">gatewayAPI.enabled</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># sample output</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">🔮 Auto-detected Kubernetes kind: AKS</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ℹ️  Using Cilium version </span><span class="token number" style="color:#36acaa">1.15</span><span class="token plain">.2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">🔮 Auto-detected cluster name: cilium-service-mesh-aks</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✅ Derived Azure subscription ID </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">subscription_id</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> from subscription Pay-As-You-Go</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✅ Detected Azure AKS cluster </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> BYOCNI mode </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">no CNI plugin pre-installed</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">🔮 Auto-detected kube-proxy has not been installed</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ℹ️  Cilium will fully replace all functionalities of kube-proxy</span><br></span></code></pre></div></div>
<p>Using <code>cilium status</code> we can monitor the progress of the deployment of cilium. Please be aware that it might take some time to have everything working. I was a bit worried to be honest because it took a long time, however in the end all worked as expected. I think the deployment time can be reduced having more powerful vms and possibly a standard load balancer.</p>
<p>When all the deployments are green validate that all is working correctly:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Execute cilium test suite</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">cilium connectivity </span><span class="token builtin class-name">test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">✅ All </span><span class="token number" style="color:#36acaa">43</span><span class="token plain"> tests </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">184</span><span class="token plain"> actions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> successful, </span><span class="token number" style="color:#36acaa">18</span><span class="token plain"> tests skipped, </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> scenarios skipped.</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cilium-service-mesh-gateway-api-http-sample">Cilium service mesh gateway api HTTP sample<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#cilium-service-mesh-gateway-api-http-sample" class="hash-link" aria-label="Direct link to Cilium service mesh gateway api HTTP sample" title="Direct link to Cilium service mesh gateway api HTTP sample" translate="no">​</a></h2>
<p>As an additional validation we can run the <a href="https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/http/" target="_blank" rel="noopener noreferrer" class="">HTTP sample found on cilium docs</a>, I won't replicate the sample from cilium docs. A couple of commands will install everything that is needed, please check cilium docs to understand how to check that everything is working correctly.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Install sample app and gateway</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">kubectl apply </span><span class="token parameter variable" style="color:#36acaa">-f</span><span class="token plain"> https://raw.githubusercontent.com/istio/istio/release-1.11/samples/bookinfo/platform/kube/bookinfo.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">kubectl apply </span><span class="token parameter variable" style="color:#36acaa">-f</span><span class="token plain"> https://raw.githubusercontent.com/cilium/cilium/1.15.2/examples/kubernetes/gateway/basic-http.yaml</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="some-screenshots-to-display-the-outcome-from-the-aks-dashboard-point-of-view">Some screenshots to display the outcome from the AKS dashboard point of view<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#some-screenshots-to-display-the-outcome-from-the-aks-dashboard-point-of-view" class="hash-link" aria-label="Direct link to Some screenshots to display the outcome from the AKS dashboard point of view" title="Direct link to Some screenshots to display the outcome from the AKS dashboard point of view" translate="no">​</a></h3>
<p>Note here the (obfuscated) public ip address automatically attached to the service</p>
<img src="https://davidelettieri.it/img/services.png" alt="Kubernetes services created by the sample">
<p>The useful CRD section in AKS dashboard showing all the resources installed by us (gateway api) and by cilium</p>
<img src="https://davidelettieri.it/img/crd.png" alt="Custom resource definitions">
<p>Instances of the resources deployed by the <code>basic-http.yaml</code> file</p>
<img src="https://davidelettieri.it/img/gateway.png" alt="The deployed gateway">
<img src="https://davidelettieri.it/img/http-route.png" alt="The deployed http route">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="azure-annotations">Azure annotations<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#azure-annotations" class="hash-link" aria-label="Direct link to Azure annotations" title="Direct link to Azure annotations" translate="no">​</a></h2>
<p>Using the experimental channel of gateway API we can use the <code>infrastructure</code> object in the gateway definition to pass annotation to the load balancer service that is created. All the available annotations can be found <a href="https://cloud-provider-azure.sigs.k8s.io/topics/loadbalancer/#loadbalancer-annotations" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">apiVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> gateway.networking.k8s.io/v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Gateway</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> my</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">gateway</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">spec</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">infrastructure</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">annotations</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">service.beta.kubernetes.io/azure-load-balancer-internal</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"true"</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="final-remarks">Final remarks<a href="https://davidelettieri.it/2024/03/21/aks-cilium-service-mesh#final-remarks" class="hash-link" aria-label="Direct link to Final remarks" title="Direct link to Final remarks" translate="no">​</a></h2>
<p>If you need to run a kubernetes cluster with restricted network at vnet level (not k8s network policies level) please be aware that cilium has some requirements <a href="https://docs.cilium.io/en/stable/operations/system_requirements/#firewall-rules" target="_blank" rel="noopener noreferrer" class="">https://docs.cilium.io/en/stable/operations/system_requirements/#firewall-rules</a>, if you have any kind of connectivity world-&gt;aks or pod-&gt;pod you will need more than that. Be aware and test everything before making the decision of using cilium.</p>]]></content:encoded>
            <category>aks</category>
            <category>cilium</category>
            <category>gateway-api</category>
            <category>k8s</category>
            <category>service-mesh</category>
        </item>
        <item>
            <title><![CDATA[Fedora, switch audio channels with pipewire]]></title>
            <link>https://davidelettieri.it/2024/02/04/fedora-pipewire-switch-channels</link>
            <guid>https://davidelettieri.it/2024/02/04/fedora-pipewire-switch-channels</guid>
            <pubDate>Sun, 11 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[The lua configuration files are valid only for wireplumber v\<0.5. Please check here for the configuration required on v=0.5. This post remains valid for what concerns retrieving the node name required in the config file.]]></description>
            <content:encoded><![CDATA[<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_BuS1"><p>The lua configuration files are valid only for wireplumber v&lt;0.5. Please <a class="" href="https://davidelettieri.it/2024/06/21/fedora-pipewire-switch-channels-wireplumber-0.5">check here</a> for the configuration required on v=0.5. This post remains valid for what concerns retrieving the node name required in the config file.</p></div></div>
<p>I bought a pair Creative Pebble V3 and given my desk setup and the cables of the 2 speakers, I needed to switch left and right audio channels in order to setup correctly the speakers.</p>
<p>Now, I'm running Fedora Workstation and I never had to troubleshoot, manage, or change any audio settings besides adjusting volume when needed. I found out this task is not as easy as it seems, probably for a mixture of lack of documentation and lack of skills on my side.</p>
<p>At first I tried some promising GUI tools:</p>
<ul>
<li class="">EasyEffects -&gt; with this one I was able to visually obtain what I wanted, ie switch channels, however I was not able to apply the changes anyhow.</li>
<li class="">qpwgraph -&gt; with this one I just got some background noise in my speakers and quickly gave up after successfully reverting the changes I made.</li>
</ul>
<p>After this I found the <code>wireplumber</code> tool and that indeed worked. This <a href="https://bbs.archlinux.org/viewtopic.php?id=285115" target="_blank" rel="noopener noreferrer" class="">Archlinux forum post</a> pointed me in the right direction, however the post sample was doing something more than just switch channels and it wasn't working for me as it is.</p>
<p>First off, be sure that wireplumber is installed and enabled in your system:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Check wireplumber status</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">wpctl status</span><br></span></code></pre></div></div>
<p>You should get an output similar to this:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">sample output</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">PipeWire </span><span class="token string" style="color:#e3116c">'pipewire-0'</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, cookie:3084944151</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> └─ Clients:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">31</span><span class="token plain">. uresourced                          </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:2636</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">32</span><span class="token plain">. WirePlumber                         </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:2666</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">33</span><span class="token plain">. WirePlumber </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">export</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:2666</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">56</span><span class="token plain">. gnome-shell                         </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:2699</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">57</span><span class="token plain">. pipewire                            </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:3375</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">58</span><span class="token plain">. GNOME Shell Volume Control          </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:2699</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">59</span><span class="token plain">. GNOME Volume Control Media Keys     </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:2914</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">60</span><span class="token plain">. xdg-desktop-portal                  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:3461</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">61</span><span class="token plain">. Google Chrome input                 </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:5148</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">62</span><span class="token plain">. Mutter                              </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:2699</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">68</span><span class="token plain">. Boxes                               </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:6646</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">69</span><span class="token plain">. wpctl                               </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:7334</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">70</span><span class="token plain">. Boxes                               </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1.0</span><span class="token plain">.1, davide@home, pid:6646</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Audio</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ├─ Devices:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> │      </span><span class="token number" style="color:#36acaa">40</span><span class="token plain">. Pebble V3                           </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">alsa</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> │      </span><span class="token number" style="color:#36acaa">41</span><span class="token plain">. Navi </span><span class="token number" style="color:#36acaa">31</span><span class="token plain"> HDMI/DP Audio               </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">alsa</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> │      </span><span class="token number" style="color:#36acaa">42</span><span class="token plain">. Starship/Matisse HD Audio Controller </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">alsa</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> │  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> ├─ Sinks:</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"> │  *   </span><span class="token number" style="color:#36acaa">43</span><span class="token plain">. Pebble V3 Analog Stereo             </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">vol: </span><span class="token number" style="color:#36acaa">1.00</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> │      </span><span class="token number" style="color:#36acaa">44</span><span class="token plain">. Starship/Matisse HD Audio Controller Analog Stereo </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">vol: </span><span class="token number" style="color:#36acaa">1.00</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">..</span><span class="token plain">.</span><br></span></code></pre></div></div>
<p>I tried this on a new VM running Fedora 39 Workstation image and it is working out of the box. The part that we are most interested in is the <code>Sinks</code> part. In my case it was the <code>Pebble V3 Analog Stereo</code> sink, the one I want to customize.</p>
<p>Let's use the ID to get more details:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">command</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">wpctl inspect </span><span class="token number" style="color:#36acaa">43</span><br></span></code></pre></div></div>
<p>Expect something like this:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">sample output</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">id</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">43</span><span class="token plain">, </span><span class="token builtin class-name">type</span><span class="token plain"> PipeWire:Interface:Node</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.card </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.card_name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Pebble V3"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.class </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"generic"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.device </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.driver_name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"snd_usb_audio"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"USB Audio"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.long_card_name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"ACTIONS Pebble V3 at usb-0000:03:00.0-9, full speed"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"USB Audio"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.resolution_bits </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"16"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.subclass </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"generic-mix"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.subdevice </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    alsa.subdevice_name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"subdevice #0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    api.alsa.card.longname </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"ACTIONS Pebble V3 at usb-0000:03:00.0-9, full speed"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    api.alsa.card.name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Pebble V3"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    api.alsa.path </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"front:0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    api.alsa.pcm.card </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    api.alsa.pcm.stream </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"playback"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    audio.adapt.follower </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    audio.channels </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2"</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    audio.position </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"FR,FL"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    card.profile.device </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * client.id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"33"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    clock.quantum-limit </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"8192"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    device.api </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"alsa"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    device.class </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sound"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * device.id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"40"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    device.profile.description </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Analog Stereo"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    device.profile.name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"analog-stereo"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    device.routes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * factory.id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"18"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    factory.mode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"merge"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    factory.name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"api.alsa.pcm.sink"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    library.name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"audioconvert/libspa-audioconvert"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * media.class </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Audio/Sink"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * node.description </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Pebble V3 Analog Stereo"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    node.driver </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"true"</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  * node.name </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"alsa_output.usb-ACTIONS_Pebble_V3-00.analog-stereo"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * node.nick </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Pebble V3"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    node.pause-on-idle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"false"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * object.path </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"alsa:pcm:0:front:0:playback"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * object.serial </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"43"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * priority.driver </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1009"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  * priority.session </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1009"</span><br></span></code></pre></div></div>
<p>There are two parts that we care about: <code>node.name</code> and <code>audio.position</code>. The first one is needed as an identifier, the ID is not stable so we can forget about it, while <code>audio.position</code> which has <code>FR,FL</code> value is the one we want to change to <code>FL,FR</code> to switch the channels.</p>
<div class="language-lua codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">.config/wireplumber/main.lua.d/51-change-channels.lua</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-lua codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">rule </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    matches </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node.name"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"equals"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"alsa_output.usb-ACTIONS_Pebble_V3-00.analog-stereo"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    apply_properties </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"audio.position"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"FR,FL"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">table</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">insert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">alsa_monitor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rules</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rule</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>I saved this file as <code>.config/wireplumber/main.lua.d/51-change-channels.lua</code> (I got this filename checking samples and post online, not sure what the initial number is referring to and I suspect it's not that relevant unless you have multiple scripts in the folder) and run</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">command</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">systemctl </span><span class="token parameter variable" style="color:#36acaa">--user</span><span class="token plain"> restart wireplumber pipewire pipewire-pulse</span><br></span></code></pre></div></div>
<p>That should be enough to have your audio channel switched. If it is not working, double check that the file has the correct format and run <code>systemctl --user status pipewire*</code> to check for errors.</p>]]></content:encoded>
            <category>linux</category>
            <category>fedora</category>
            <category>pipewire</category>
            <category>wireplumber</category>
        </item>
        <item>
            <title><![CDATA[TreeSitter C# bindings - new languages]]></title>
            <link>https://davidelettieri.it/2023/11/18/Tree-sitter-C-sharp-bindings-new-languages</link>
            <guid>https://davidelettieri.it/2023/11/18/Tree-sitter-C-sharp-bindings-new-languages</guid>
            <pubDate>Sat, 18 Nov 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[I updated my TreeSitter.Bindings packages to support additional languages. I wanted to check how solid the bindings were and if I could implement a more complex sample with the respect to the json one I started with.]]></description>
            <content:encoded><![CDATA[<p>I updated my <a href="https://www.nuget.org/packages/TreeSitter.Bindings/0.0.2" target="_blank" rel="noopener noreferrer" class=""><code>TreeSitter.Bindings</code></a> packages to support additional languages. I wanted to check how solid the bindings were and if I could implement a more complex sample with the respect to the json one I started with.</p>
<p>The tree-sitter documentation provides a <a href="https://tree-sitter.github.io/tree-sitter/using-parsers#multi-language-documents" target="_blank" rel="noopener noreferrer" class="">multilanguage sample</a> which involves three languages:</p>
<ul>
<li class="">embedded template</li>
<li class="">ruby</li>
<li class="">html</li>
</ul>
<p>Luckily for me, my poor understanding of c/c++ build stack and lack of skills regarding scripting didn't stop me.</p>
<p>I was able to update <code>TreeSitter.Bindings</code> with the bindings for the new libraries, update the runtime packages to include the compiled libraries of the new languages (using version <code>0.20.8-extra.1</code>).</p>
<p>The sample project in the <a href="https://github.com/davidelettieri/treesitter-bindings" target="_blank" rel="noopener noreferrer" class="">repo</a> now provides both samples:</p>
<ul>
<li class="">json</li>
<li class="">multilanguage</li>
</ul>
<p>I suggest to run it in the provided Dev Container. If not possible install <code>libcxx</code> in your linux distribution.</p>
<p>Here is a sample code</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">Program.cs</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">ClangSharp</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Interop</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">TreeSitter</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Bindings</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">TreeSitter</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Bindings</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">EmbdeddedTemplate</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">TSBindingsEmbdeddedTemplate</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">TreeSitter</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Bindings</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Html</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">TSBindingsHtml</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">TreeSitter</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Bindings</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Ruby</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">TSBindingsRuby</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">TreeSitter</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Bindings</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">TSBindings</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">unsafe</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">WriteLine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"-- Multi language sample --"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">MultiLanguageDocumentSample</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token return-type class-name keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">MultiLanguageDocumentSample</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> parser </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parser_new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">parser_set_language</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_sitter_embedded_template</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">MarshaledString</span><span class="token plain"> sourceCode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">MarshaledString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"&lt;ul&gt;\n  &lt;% people.each do |person| %&gt;\n    &lt;li&gt;&lt;%= person.name %&gt;&lt;/li&gt;\n  &lt;% end %&gt;\n&lt;/ul&gt;"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        TSTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parser_parse_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            sourceCode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">uint</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> sourceCode</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">TSNode</span><span class="token plain"> erbRootNode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_root_node</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> childCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">erbRootNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">TSRange</span><span class="token class-name punctuation" style="color:#393A34">[</span><span class="token class-name punctuation" style="color:#393A34">]</span><span class="token plain"> htmlRanges </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">TSRange</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">childCount</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">TSRange</span><span class="token class-name punctuation" style="color:#393A34">[</span><span class="token class-name punctuation" style="color:#393A34">]</span><span class="token plain"> rubyRanges </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">TSRange</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">childCount</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name keyword" style="color:#00009f">uint</span><span class="token plain"> htmlRangesCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name keyword" style="color:#00009f">uint</span><span class="token plain"> rubyRangesCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">uint</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> childCount</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">TSNode</span><span class="token plain"> node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_child</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">erbRootNode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_type</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"content"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> htmlRange </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">TSRange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    start_point </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_start_point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    end_point </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_end_point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    start_byte </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_start_byte</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    end_byte </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_end_byte</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                htmlRanges</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">htmlRangesCount</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> htmlRange</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name">TSNode</span><span class="token plain"> codeNode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_named_child</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">node</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> rubyRange </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">TSRange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    start_point </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_start_point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">codeNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    end_point </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_end_point</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">codeNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    start_byte </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_start_byte</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">codeNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    end_byte </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_end_byte</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">codeNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                rubyRanges</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">rubyRangesCount</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> rubyRange</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">fixed</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TSRange</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ph </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">htmlRanges</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">fixed</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">TSRange</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> pr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">rubyRanges</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">parser_set_language</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_sitter_html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">parser_set_included_ranges</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ph</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> htmlRangesCount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            TSTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> htmlTree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parser_parse_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sourceCode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">uint</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> sourceCode</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">TSNode</span><span class="token plain"> htmlRootNode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_root_node</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">htmlTree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">parser_set_language</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_sitter_ruby</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">parser_set_included_ranges</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> pr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rubyRangesCount</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            TSTree</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> rubyTree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parser_parse_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sourceCode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">uint</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> sourceCode</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">TSNode</span><span class="token plain"> rubyRootNode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_root_node</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rubyTree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token plain"> erbSexp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">erbRootNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token plain"> htmlSexp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">htmlRootNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token plain"> rubySexp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rubyRootNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">WriteLine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">erbSexp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">WriteLine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">htmlSexp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">WriteLine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rubySexp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The result is</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">output</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">-- Multi language sample --</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">template </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">directive </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">code</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">output_directive </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">code</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">directive </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">code</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">content</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">fragment </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">element </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">start_tag </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tag_name</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">element </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">start_tag </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tag_name</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">end_tag </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tag_name</span><span class="token punctuation" style="color:#393A34">))</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">end_tag </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tag_name</span><span class="token punctuation" style="color:#393A34">))</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">program </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">call receiver: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">identifier</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> method: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">identifier</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> block: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">do_block parameters: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">block_parameters </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">identifier</span><span class="token punctuation" style="color:#393A34">))</span><span class="token plain"> body: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">body_statement </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">call receiver: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">identifier</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> method: </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">identifier</span><span class="token punctuation" style="color:#393A34">))</span><span class="token punctuation" style="color:#393A34">))</span><span class="token punctuation" style="color:#393A34">))</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>c#</category>
            <category>tree-sitter</category>
            <category>c#-bindings</category>
            <category>tree-sitter-ruby</category>
            <category>tree-sitter-html</category>
            <category>tree-sitter-embedded-template</category>
        </item>
        <item>
            <title><![CDATA[Flux and SOPS on AKS with workload identity]]></title>
            <link>https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity</link>
            <guid>https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity</guid>
            <pubDate>Wed, 01 Nov 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[The post and the repository has been updated on 07-05-2025 to use latest versions of sops, kubectl, azure apis. The devcontainer is modified to be able to use it with podman.]]></description>
            <content:encoded><![CDATA[<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>The post and the repository has been updated on 07-05-2025 to use latest versions of sops, kubectl, azure apis. The devcontainer is modified to be able to use it with podman.</p></div></div>
<p>Setting up sops with flux and workload identity on AKS is not a complex procedure however there is a lack of proper documentation for some steps.</p>
<p>I was working on setting this up on Azure Kubernetes Service and getting stuck at the point where I had to actually decrypt a secret from a sample deployment.</p>
<p>The key point to understand is that the application responsible for decrypting the secrets is the <code>kustomize-controller</code>. We aim then to have a managed identity assigned to the <code>service-account</code> of the <code>kustomize-controller</code> deployed by flux and to enable workload identity on both the service account and the pods. This requires some azure specific labels and annotations to be added to the k8s resources.</p>
<p>I aim to provide a recap on how to deploy all of this with links to the relevant documentation and add the sample yaml needed to assign and use the identity.</p>
<p>We aim to have:</p>
<ul>
<li class="">An AKS cluster deployed with workload identity enabled</li>
<li class="">A managed identity with a federated credential</li>
<li class="">A key vault to store the encryption key, an encryption key and access policy to allow the managed identity to encrypt using the key</li>
<li class="">A github repo to be our source of truth for k8s deployment</li>
<li class="">Flux deployed in the cluster</li>
<li class="">Flux resources patched to enable workload identity</li>
<li class="">A sample encrypted secret in the repo</li>
</ul>
<p>If you just want to check the end result <a href="https://github.com/davidelettieri/flux-sops-workload-identity" target="_blank" rel="noopener noreferrer" class="">this is the repo with all the files.</a></p>
<p><strong>Please note that there some values in the files and scripts that needs to be updated according to your environment, such as resource group name or reference to github repo.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="required-tooling-on-workstation">Required tooling on workstation<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#required-tooling-on-workstation" class="hash-link" aria-label="Direct link to Required tooling on workstation" title="Direct link to Required tooling on workstation" translate="no">​</a></h2>
<p>We will use:</p>
<ul>
<li class="">az CLI</li>
<li class="">Flux CLI</li>
<li class="">sops CLI</li>
</ul>
<p>In addition to that but not strictly required:</p>
<ul>
<li class="">vs code with bicep extension for code editing</li>
<li class="">kubectl for troubleshooting/inspection of k8s cluster</li>
</ul>
<p>I'll perform the deployment from a devcontainer based on debian with all the tools required already installed but of course this is doable from any Windows/Linux machine and from WSL within Windows.</p>
<p>I will add some description for all the steps below and I will provide a repo with all the scripts and yaml files organized into two folders:</p>
<ul>
<li class="">iac</li>
<li class="">gitops</li>
</ul>
<p>A better approach would be to have two github repos, one for infrastructure, one for k8s deployment. However I want to keep things manageable for this post and I'll use just one repo. I structured the azure resources in 3 modules, described below. A <code>main.bicep</code> file put everything together.</p>
<p>The <code>iac</code> folder contains a <code>deploy.sh</code> script that execute the bicep deployment.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="aks-with-workload-identity-enabled---aksbicep">AKS with workload identity enabled - aks.bicep<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#aks-with-workload-identity-enabled---aksbicep" class="hash-link" aria-label="Direct link to AKS with workload identity enabled - aks.bicep" title="Direct link to AKS with workload identity enabled - aks.bicep" translate="no">​</a></h2>
<p>There are several options to deploy a workload enabled cluster on Azure. My preferred option is to go with <code>bicep</code>, since it has decent tooling and it is idempotent by default.</p>
<p>Regardless of the deployment method, we need to enable workload identity and get the OIDC issuer URL for the cluster to be used in a subsequent step.</p>
<p>The OIDC Issuer URL is required to set up the federated credentials on the managed identity that's why we have it as an output.</p>
<p>This is my sample deployment.</p>
<div class="language-bicep codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">aks.bicep</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bicep codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">param</span><span class="token plain"> location </span><span class="token datatype class-name">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">resource</span><span class="token plain"> aks </span><span class="token string" style="color:#e3116c">'Microsoft.ContainerService/managedClusters@2025-02-01'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'my-aks'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">location</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">identity</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">type</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'SystemAssigned'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">sku</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Base'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">tier</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Free'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">properties</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">kubernetesVersion</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'1.32'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">agentPoolProfiles</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'system'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">mode</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'System'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">vmSize</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Standard_B2ms'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">count</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">enableAutoScaling</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">osType</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Linux'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">osSKU</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'AzureLinux'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">dnsPrefix</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'my-aks-dns'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">oidcIssuerProfile</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">enabled</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">securityProfile</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">workloadIdentity</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">enabled</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">networkProfile</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">loadBalancerSku</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'basic'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">output</span><span class="token plain"> oidcIssuerURL </span><span class="token datatype class-name">string</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> aks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">oidcIssuerProfile</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">issuerURL</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="managed-identity---mibicep">Managed identity - mi.bicep<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#managed-identity---mibicep" class="hash-link" aria-label="Direct link to Managed identity - mi.bicep" title="Direct link to Managed identity - mi.bicep" translate="no">​</a></h2>
<p>The managed identity is going to be used by the <code>kustomize-controller</code> to get access to the encryption key. The service account of the kustomize-controller has an account token that is going to be exchanged with an azure ad token that will permit access to the key-vault.</p>
<p>We will use the principal id to allow the managed identity to access the encryption key.</p>
<div class="language-bicep codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">mi.bicep</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bicep codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">param</span><span class="token plain"> location </span><span class="token datatype class-name">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">param</span><span class="token plain"> aksIssuerURL </span><span class="token datatype class-name">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">resource</span><span class="token plain"> managedIdentity </span><span class="token string" style="color:#e3116c">'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'kustomize-controller-mi'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">location</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">resource</span><span class="token plain"> federatedCredentials </span><span class="token string" style="color:#e3116c">'Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials@2024-11-30'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'aks-fc'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">parent</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> managedIdentity</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">properties</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">audiences</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">'api://AzureADTokenExchange'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">issuer</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> aksIssuerURL</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">subject</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'system:serviceaccount:flux-system:kustomize-controller'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">output</span><span class="token plain"> objectId </span><span class="token datatype class-name">string</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> managedIdentity</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">principalId</span><br></span></code></pre></div></div>
<p>The <code>subject</code> field for a federated credential for a Kubernetes service accounts always follow the same pattern: <code>system:serviceaccount:[namespace]:[service account name]</code>. Please also note that every namespace in Kubernetes as a default service account so you might not need to create a new one. In this particular case I'm using the namespace and the service account flux is creating.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="keyvault---kvbicep">KeyVault - kv.bicep<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#keyvault---kvbicep" class="hash-link" aria-label="Direct link to KeyVault - kv.bicep" title="Direct link to KeyVault - kv.bicep" translate="no">​</a></h2>
<p>Deploy a key vault with bicep, adding an encryption key and relevant access policies.</p>
<div class="language-bicep codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">kv.bicep</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bicep codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">pparam location string</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">param</span><span class="token plain"> managedIdentityObjectId </span><span class="token datatype class-name">string</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">resource</span><span class="token plain"> keyVault </span><span class="token string" style="color:#e3116c">'Microsoft.KeyVault/vaults@2024-11-01'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token interpolated-string string" style="color:#e3116c">'my-kv-</span><span class="token interpolated-string interpolation punctuation" style="color:#393A34">${</span><span class="token interpolated-string interpolation expression function" style="color:#d73a49">uniqueString</span><span class="token interpolated-string interpolation expression punctuation" style="color:#393A34">(</span><span class="token interpolated-string interpolation expression function" style="color:#d73a49">resourceGroup</span><span class="token interpolated-string interpolation expression punctuation" style="color:#393A34">(</span><span class="token interpolated-string interpolation expression punctuation" style="color:#393A34">)</span><span class="token interpolated-string interpolation expression punctuation" style="color:#393A34">.</span><span class="token interpolated-string interpolation expression">id</span><span class="token interpolated-string interpolation expression punctuation" style="color:#393A34">)</span><span class="token interpolated-string interpolation punctuation" style="color:#393A34">}</span><span class="token interpolated-string string" style="color:#e3116c">'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">location</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> location</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">properties</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">sku</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">family</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'A'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'standard'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">tenantId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tenant</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tenantId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">accessPolicies</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">objectId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> managedIdentityObjectId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">tenantId</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tenant</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tenantId</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">permissions</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token property" style="color:#36acaa">keys</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token string" style="color:#e3116c">'get'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token string" style="color:#e3116c">'decrypt'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">resource</span><span class="token plain"> key </span><span class="token string" style="color:#e3116c">'Microsoft.KeyVault/vaults/keys@2024-11-01'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'encryption-key'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">parent</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> keyVault</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">properties</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">attributes</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">enabled</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">exportable</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">kty</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'RSA'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">keySize</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2048</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="github-repo">Github repo<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#github-repo" class="hash-link" aria-label="Direct link to Github repo" title="Direct link to Github repo" translate="no">​</a></h2>
<p>We will use <a href="https://github.com/davidelettieri/flux-sops-workload-identity" target="_blank" rel="noopener noreferrer" class="">this repo</a> to bootstrap Flux, you want to have a dedicated repo but as I said before I'll keep all the code from the blog post in a single repo, including infrastructure as code part.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bootstrap-flux">Bootstrap flux<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#bootstrap-flux" class="hash-link" aria-label="Direct link to Bootstrap flux" title="Direct link to Bootstrap flux" translate="no">​</a></h2>
<p>In the <code>gitops</code> folder of the repo, the <code>setup-flux.sh</code> script I used to setup flux. Please note that the inner <code>aks</code> folder was empty when I ran the script.</p>
<p>Please update the script to refer to your github account or check Flux documentation for additional providers.</p>
<p>If you will use GitHub then you will be prompted for a personal access token, create one with repo access. A short expiration date is fine, Flux will add a deploy key to the repo to access it in the future.</p>
<p><a href="https://fluxcd.io/flux/installation/bootstrap/github/#github-personal-account" target="_blank" rel="noopener noreferrer" class="">Flux documentation</a> states</p>
<blockquote>
<p>Note that the GitHub PAT is stored in the cluster as a Kubernetes Secret named flux-system inside the flux-system namespace. If you want to avoid storing your PAT in the cluster, please see how to configure GitHub Deploy Keys.</p>
</blockquote>
<p>I'm checking today 07-05-2025 and, as I noticed before, the GitHub PAT is not stored into the <code>flux-system</code> secret as shown in the following screenshot. A newly created deploy key is contained in the secret.</p>
<figure><img style="margin:0 auto;display:block" alt="Flux system secret content" src="https://davidelettieri.it/img/flux-system-secret.png"><figcaption>Flux system secret content</figcaption></figure>
<div class="theme-admonition theme-admonition-danger admonition_xJq3 alert alert--danger"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"></path></svg></span>danger</div><div class="admonitionContent_BuS1"><p>The token can have a very short expiration date and it will be used only during bootstrap phase. However you <strong>cannot</strong> delete the token after it is used or expired because doing so will invalidate the deploy key.</p></div></div>
<p>When the command is complete the <code>aks</code> folder is populated with a <code>flux-system</code> sub-folder.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="patch-flux">Patch flux<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#patch-flux" class="hash-link" aria-label="Direct link to Patch flux" title="Direct link to Patch flux" translate="no">​</a></h2>
<p>Now we have to "assign" the managed identity to the service account and to enable workload identity. This is the step for which I couldn't find any documentation.</p>
<p>To do that we will <em>patch</em> two resources created by Flux. I like to organize patches into a subfolder <code>patches</code> and have one file per resource.</p>
<p>Expected structure is:</p>
<ul>
<li class="">gitops:<!-- -->
<ul>
<li class="">aks:<!-- -->
<ul>
<li class="">flux-system:<!-- -->
<ul>
<li class="">gotk-components.yaml</li>
<li class="">gotk-sync.yaml</li>
<li class="">kustomization.yaml <strong>[TO MODIFY]</strong></li>
<li class="">patches:<!-- -->
<ul>
<li class="">kustomize-controller-deployment.yaml <strong>[NEW]</strong></li>
<li class="">kustomize-controller-service-account.yaml <strong>[NEW]</strong></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The <code>kustomization.yaml</code> files has to be updated to</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">apiVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> kustomize.config.k8s.io/v1beta1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Kustomization</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">resources</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> gotk</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">components.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> gotk</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">sync.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">patches</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> patches/kustomize</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">controller</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">deployment.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> patches/kustomize</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">controller</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">service</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">account.yaml</span><br></span></code></pre></div></div>
<p>The <code>kustomize-controller-deployment.yaml</code> can be copied as it is, while for the <code>kustomize-controller-service-account.yaml</code> you will need to retrieve client id and tenant id for the deployed managed identity.</p>
<p>You can use the following command, possibly updating the value of the resource group name.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">az identity list </span><span class="token parameter variable" style="color:#36acaa">-g</span><span class="token plain"> flux-workload-identity-post </span><span class="token parameter variable" style="color:#36acaa">--query</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"[].{clientId: clientId, tenantId: tenantId }"</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--output</span><span class="token plain"> table</span><br></span></code></pre></div></div>
<p>Update the yaml with the relevant values</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">apiVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ServiceAccount</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> kustomize</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">controller</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">namespace</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> flux</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">system</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">annotations</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">azure.workload.identity/client-id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> &lt;your value</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">azure.workload.identity/tenant-id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> &lt;your value</span><span class="token punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">labels</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">azure.workload.identity/use</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"true"</span><br></span></code></pre></div></div>
<p>Now commit all the changes and push. It will take a few minutes to complete the deployment.
You can check the status using:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">flux get all </span><span class="token parameter variable" style="color:#36acaa">-A</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="add-a-sample-secret">Add a sample secret<a href="https://davidelettieri.it/2023/11/01/flux-and-sops-on-aks-with-workload-identity#add-a-sample-secret" class="hash-link" aria-label="Direct link to Add a sample secret" title="Direct link to Add a sample secret" translate="no">​</a></h2>
<p>Let's see the result from a file-system point of view, please setup files and folder as shown below. My <a href="https://github.com/davidelettieri/flux-sops-workload-identity" target="_blank" rel="noopener noreferrer" class="">repo</a> has this final setup. Having a structure exactly like this one is probably not required, I'm not an expert on flux nor gitops, feel free to adjust to your needs.</p>
<ul>
<li class="">gitops:<!-- -->
<ul>
<li class="">aks:<!-- -->
<ul>
<li class="">kustomization.yaml <strong>[NEW]</strong></li>
<li class="">apps.yaml <strong>[NEW]</strong></li>
<li class="">apps:<!-- -->
<ul>
<li class="">kustomization.yaml <strong>[NEW]</strong></li>
<li class="">namespace.yaml <strong>[NEW]</strong></li>
<li class="">secret.yaml <strong>[NEW]</strong></li>
</ul>
</li>
<li class="">flux-system:<!-- -->
<ul>
<li class="">gotk-components.yaml</li>
<li class="">gotk-sync.yaml</li>
<li class="">kustomization.yaml</li>
<li class="">patches:<!-- -->
<ul>
<li class="">kustomize-controller-deployment.yaml</li>
<li class="">kustomize-controller-service-account.yaml</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>You can copy the content of all files except for <code>secret.yaml</code> and possibly <code>apps.yaml</code>. Let's start with the latter:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">apiVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> kustomize.toolkit.fluxcd.io/v1beta2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Kustomization</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> apps</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">namespace</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> flux</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">system</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">spec</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">dependsOn</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> flux</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">system</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">interval</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> 2m0s</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">sourceRef</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> GitRepository</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> flux</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">system</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> ./gitops/aks/apps </span><span class="token comment" style="color:#999988;font-style:italic"># if your folder structure is different change this path to reflect where you want to deploy the secret</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">prune</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">wait</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">timeout</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> 5m0s</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">decryption</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">provider</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> sops </span><span class="token comment" style="color:#999988;font-style:italic"># here we are telling flux that we are using sops</span><br></span></code></pre></div></div>
<p>For the secret, mine is already encrypted but we have to start with a clear text one</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">apiVersion</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">kind</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Secret</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">metadata</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> sample</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">secret</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">namespace</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> sops</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">workload</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">identity</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">type</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Opaque</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">stringData</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">sops_encrypted_secret</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> value of the secret</span><br></span></code></pre></div></div>
<p>With the following command</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">sops </span><span class="token parameter variable" style="color:#36acaa">-e</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">-i</span><span class="token plain"> --encrypted-regex </span><span class="token string" style="color:#e3116c">'^(data|stringData)$'</span><span class="token plain"> --azure-kv </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">url to the encryption key</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> secret.yaml</span><br></span></code></pre></div></div>
<p>This will encrypt only the <code>stringData</code> part, however all the file content is added to the checksum so it cannot be changed outside of sops. From now on, to edit the secret run <code>sops secret.yaml</code>.</p>
<p>Now commit and push. After the deployment is completed, your cluster should have access to the secret:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">kubectl get secret sample-secret </span><span class="token parameter variable" style="color:#36acaa">-n</span><span class="token plain"> sops-workload-identity </span><span class="token parameter variable" style="color:#36acaa">-o</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">jsonpath</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'{.data.*}'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> base64 </span><span class="token parameter variable" style="color:#36acaa">-d</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>kubernetes</category>
            <category>aks</category>
            <category>azure</category>
            <category>flux</category>
            <category>sops</category>
            <category>gitops</category>
        </item>
        <item>
            <title><![CDATA[Implementing APIs with the visitor pattern]]></title>
            <link>https://davidelettieri.it/2023/06/24/Implementing-apis-with-the-visitor-pattern</link>
            <guid>https://davidelettieri.it/2023/06/24/Implementing-apis-with-the-visitor-pattern</guid>
            <pubDate>Fri, 16 Jun 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[I want to leverage my visitor pattern source generator to implement a simple minimal api.]]></description>
            <content:encoded><![CDATA[<p>I want to leverage my <a href="https://github.com/davidelettieri/visitor-generator" target="_blank" rel="noopener noreferrer" class="">visitor pattern source generator</a> to implement a simple minimal api.</p>
<p>I aim to:</p>
<ul>
<li class="">Have a request and a request handler for my endpoint. I will not use mediatr or any similar library and I will not use any real storage, only some in memory data structure to showcase the visitor pattern approach.</li>
<li class="">The request handler <code>Handle</code> method returns an interface, every subtype represents a different type of result, a success, and one type for each error (provided) emitted by the handled.</li>
<li class="">For each subtype we want to be able to return a possibly different http response.</li>
</ul>
<p>To do this it is not required to leverage the visitor pattern and we can make it just with pattern matching. However the pattern matching approach, with its current capabilities, will not check for exaustiveness and if we add a new result type we will in the best case get an error during testing or worse at runtime.</p>
<p>Moreover if we have multiple places where we are using pattern matching we have to remember to update all of them. The visitor pattern can be more easily updatable because once the interface of the visitor is updated, the build will be broken, signaling where a change is needed. If the interface is auto-generated this is even simpler since you cannot forget to update the visitor interface.</p>
<p>I won't provide a full repo, code listing is just one file with everything inside it.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">VisitorGenerator</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// this namespace is coming from my visitor source generator. </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// It's hosted on github registry, here is the repo https://github.com/davidelettieri/visitor-generator</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> builder </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> WebApplication</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">CreateBuilder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">args</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Services</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-method function" style="color:#d73a49">AddSingleton</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&lt;</span><span class="token generic-method generic class-name">CreateProductRequestHandler</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Services</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generic-method function" style="color:#d73a49">AddSingleton</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&lt;</span><span class="token generic-method generic class-name">ProductResultVisitor</span><span class="token generic-method generic class-name punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Services</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">AddEndpointsApiExplorer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">builder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Services</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">AddSwaggerGen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> app </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> builder</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Build</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Configure the HTTP request pipeline.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Environment</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">IsDevelopment</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">UseSwagger</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">UseSwaggerUI</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">UseHttpsRedirection</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">MapPost</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/product"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// this contains the user input</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">CreateProductRequest</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// this contains the domain logic</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">CreateProductRequestHandler</span><span class="token plain"> handler</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// this will map the result obtained by our domain to an http result.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">ProductResultVisitor</span><span class="token plain"> visitor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> handler</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Handle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Accept</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">visitor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">WithName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"CreateProduct"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">WithOpenApi</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">app</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CreateProductRequest</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">int</span><span class="token return-type class-name punctuation" style="color:#393A34">?</span><span class="token plain"> CategoryId </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">string</span><span class="token return-type class-name punctuation" style="color:#393A34">?</span><span class="token plain"> Name </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// the attribute is coming from my nuget package. </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// All the types are marked partial because </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// the source generator will add code to all of them. </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// This is a requirement to use my package, but</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// you can roll your own types and visitors manually. </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Probably there are other libraries to do a similar</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// work if you want to avoid using mine or doing it manually.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token attribute class-name">VisitorNode</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">partial</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name">ICreateProductResult</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// After the base type, we define all our possible results.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">partial</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ProductCreated</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">ICreateProductResult</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ProductCreated</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Guid</span><span class="token plain"> productId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ProductId </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> productId</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">Guid</span><span class="token plain"> ProductId </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">partial</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">NameIsMandatory</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">ICreateProductResult</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">partial</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CategoryNotFound</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">ICreateProductResult</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">partial</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">NameAlreadyExisting</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">ICreateProductResult</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// The ICreateProductResultVisitor&lt;T&gt; interfaces is generated automatically</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// if you add a new result type this visitor will need to implement a new method.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// this will allow you to keep your code updated.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">ProductResultVisitor</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">ICreateProductResultVisitor</span><span class="token type-list class-name punctuation" style="color:#393A34">&lt;</span><span class="token type-list class-name">IResult</span><span class="token type-list class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">IResult</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Visit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ProductCreated</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> Results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Created</span><span class="token punctuation" style="color:#393A34">(</span><span class="token interpolation-string string" style="color:#e3116c">$"/product/</span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">{</span><span class="token interpolation-string interpolation expression language-csharp">node</span><span class="token interpolation-string interpolation expression language-csharp punctuation" style="color:#393A34">.</span><span class="token interpolation-string interpolation expression language-csharp">ProductId</span><span class="token interpolation-string interpolation punctuation" style="color:#393A34">}</span><span class="token interpolation-string string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">IResult</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Visit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">NameIsMandatory</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> Results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">BadRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{ message: 'Name is mandatory' }"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">IResult</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Visit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">CategoryNotFound</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> Results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">BadRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{ message: 'Category not found' }"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">IResult</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Visit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">NameAlreadyExisting</span><span class="token plain"> node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> Results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">BadRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{ message: 'Name already existing' }"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// The handler implementation is not really important. </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// It is using some in memory data structure to perform a kind of validation. </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// We just want to be able to test all our results type. </span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CreateProductRequestHandler</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> </span><span class="token class-name">Dictionary</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name keyword" style="color:#00009f">int</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"> _categories </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Category 1"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Category 2"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Category 3"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> </span><span class="token class-name">Dictionary</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name keyword" style="color:#00009f">int</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> Dictionary</span><span class="token class-name punctuation" style="color:#393A34">&lt;</span><span class="token class-name">Guid</span><span class="token class-name punctuation" style="color:#393A34">,</span><span class="token class-name"> </span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token class-name punctuation" style="color:#393A34">&gt;</span><span class="token plain"> _products </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">ICreateProductResult</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Handle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">CreateProductRequest</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CategoryId </span><span class="token keyword" style="color:#00009f">is</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">CategoryNotFound</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">_categories</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ContainsKey</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CategoryId</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">CategoryNotFound</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">IsNullOrWhiteSpace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">NameIsMandatory</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_products</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ContainsKey</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CategoryId</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">           _products</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CategoryId</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Values</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Contains</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">NameAlreadyExisting</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Guid</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">NewGuid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">_products</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ContainsKey</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CategoryId</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            _products</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CategoryId</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        _products</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CategoryId</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Value</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">ProductCreated</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>c#</category>
            <category>visitor-pattern</category>
            <category>minimal-api</category>
        </item>
        <item>
            <title><![CDATA[TreeSitter C# bindings]]></title>
            <link>https://davidelettieri.it/2023/04/09/Tree-sitter-C-sharp-bindings</link>
            <guid>https://davidelettieri.it/2023/04/09/Tree-sitter-C-sharp-bindings</guid>
            <pubDate>Sun, 09 Apr 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[In a previous experiment I made I used the LLVMSharp library and I was quite curious on how the bindings are made. In the readme is it stated they are generated using che ClangSharp library, this one auto-generate hitself from the headers of Clang C header.]]></description>
            <content:encoded><![CDATA[<p>In a previous experiment I made I used the LLVMSharp library and I was quite curious on how the bindings are made. In the readme is it stated they are generated using che ClangSharp library, this one auto-generate hitself from the headers of Clang C header.</p>
<p>This functionality is exposed through a dotnet tool: ClangSharpPInvokeGenerator. So I wanted to try and hack my way into parsing the tree-sitter headers and use the generated code to run a very small sample using C#, in particular I was aiming for the one that's in the getting started section of the docs</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Filename - test-json-parser.c</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;assert.h&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;string.h&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;stdio.h&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;tree_sitter/api.h&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Declare the `tree_sitter_json` function, which is</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// implemented by the `tree-sitter-json` library.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">TSLanguage </span><span class="token operator" style="color:#393A34">*</span><span class="token function" style="color:#d73a49">tree_sitter_json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Create a parser.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  TSParser </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">parser </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ts_parser_new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Set the parser's language (JSON in this case).</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">ts_parser_set_language</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_sitter_json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Build a syntax tree based on source code stored in a string.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">char</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">source_code </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"[1, null]"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  TSTree </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ts_parser_parse_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token constant" style="color:#36acaa">NULL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    source_code</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">strlen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">source_code</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Get the root node of the syntax tree.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  TSNode root_node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ts_tree_root_node</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Get some child nodes.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  TSNode array_node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ts_node_named_child</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root_node</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  TSNode number_node </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ts_node_named_child</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">array_node</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Check that the nodes have the expected types.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">strcmp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">ts_node_type</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"document"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">strcmp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">ts_node_type</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">array_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"array"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">strcmp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">ts_node_type</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">number_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"number"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Check that the nodes have the expected child counts.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">ts_node_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">ts_node_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">array_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">ts_node_named_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">array_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">ts_node_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">number_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Print the syntax tree as an S-expression.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">char</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">string </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ts_node_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">root_node</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">printf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Syntax tree: %s\n"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Free all of the heap-allocated memory.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">free</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">ts_tree_delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">ts_parser_delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-clangsharppinvokegenerator-to-create-c-bindings-for-tree-sitter">Using ClangSharpPInvokeGenerator to create C# bindings for tree-sitter<a href="https://davidelettieri.it/2023/04/09/Tree-sitter-C-sharp-bindings#using-clangsharppinvokegenerator-to-create-c-bindings-for-tree-sitter" class="hash-link" aria-label="Direct link to Using ClangSharpPInvokeGenerator to create C# bindings for tree-sitter" title="Direct link to Using ClangSharpPInvokeGenerator to create C# bindings for tree-sitter" translate="no">​</a></h2>
<p>The ClangSharpPInvokeGenerator tool comes with some challenges to make it work. The readme of the <a href="https://github.com/dotnet/ClangSharp" target="_blank" rel="noopener noreferrer" class="">repo</a> is quite useful and digging into the issues also helps if you get stuck.</p>
<p>At first run it wasn't working but the error message was quite useful and I ended up downloading this <a href="https://www.nuget.org/packages/libClangSharp.runtime.linux-x64/15.0.0" target="_blank" rel="noopener noreferrer" class="">nuget package</a> and copying the files where the tool was looking for them.</p>
<p>Additionally on my Fedora box, I had to install a missing dependency</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">sudo</span><span class="token plain"> dnf </span><span class="token function" style="color:#d73a49">install</span><span class="token plain"> ncurses-compat-libs.x86_64</span><br></span></code></pre></div></div>
<p>After the tool is running you will want to pass the correct parameters to generate the bindings. The <code>tree-sitter</code> repo was simple enough to navigate and I decided quickly that I wanted to generate the bindings for the 2 headers found in the folder <code>lib/include/tree_sitter</code>:</p>
<ul>
<li class=""><code>api.h</code></li>
<li class=""><code>parser.h</code></li>
</ul>
<p>My configuration file was strongly inspired by the one used in the ClangSharp repo, which you can find <a href="https://github.com/dotnet/ClangSharp/blob/main/sources/ClangSharpPInvokeGenerator/Properties/GenerateClang.rsp" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="bindings-for-tree-sitter-json">Bindings for tree-sitter-json<a href="https://davidelettieri.it/2023/04/09/Tree-sitter-C-sharp-bindings#bindings-for-tree-sitter-json" class="hash-link" aria-label="Direct link to Bindings for tree-sitter-json" title="Direct link to Bindings for tree-sitter-json" translate="no">​</a></h3>
<p>The tree-sitter library has a set of predefined grammars, the get started project uses the tree-sitter-json grammar which is published in its own repo. In order to complete the demo code I have to generate bindings also for that one.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="some-options-are-broken-with-the-current-clangsharppinvokegenerator-release">Some options are broken with the current ClangSharpPInvokeGenerator release<a href="https://davidelettieri.it/2023/04/09/Tree-sitter-C-sharp-bindings#some-options-are-broken-with-the-current-clangsharppinvokegenerator-release" class="hash-link" aria-label="Direct link to Some options are broken with the current ClangSharpPInvokeGenerator release" title="Direct link to Some options are broken with the current ClangSharpPInvokeGenerator release" translate="no">​</a></h3>
<p>With the configuration I used it was necessary to use the <code>generate-helper-types</code> option to have some additional types in the generated output. However this was not working so I removed the option and copied the files from the ClangSharp repo. In addition to that I had a class generated twice, I'm not sure why and I might did into this a bit deeper in the future but for the sake of the experiment it was good enough to clean up manually the duplicated class.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="packaging-the-bindings-library">Packaging the bindings library<a href="https://davidelettieri.it/2023/04/09/Tree-sitter-C-sharp-bindings#packaging-the-bindings-library" class="hash-link" aria-label="Direct link to Packaging the bindings library" title="Direct link to Packaging the bindings library" translate="no">​</a></h2>
<p>I want to be able to share and use without too much hassle the bindings I generated. This requires:</p>
<ol>
<li class="">Package the project with the generated bindings</li>
<li class="">Distribute the compiled tree-sitter library</li>
</ol>
<p>Point 1 is easy and I've done it several times, I'm publishing on github nuget registry since I find it very convenient to test packages. Point 2 is a bit tricky, since the compiled tree-sitter library is depending on the combination of os and architecture.</p>
<p>Again the ClangSharp and the LLVMSharp projects already faced the same problem and they solved it somehow, even if not completely due to lack of tooling and support in the nuget infrastructure.</p>
<p>Since I wanted to make this a one-day experiment (more or less!) I decided to settle on supporting only one architecture: <code>linux-x64</code> which was the one I was using.</p>
<p>The approach is the following:</p>
<ul>
<li class="">create a <code>libtreesitter</code> <em>meta-package</em>, this will reference other packages based on the runtime.</li>
<li class="">create a <code>libtreesitter.runtime.linux-64</code> package, this package contains the compiled libraries for linux-x64:<!-- -->
<ul>
<li class=""><code>libtree-sitter.so</code></li>
<li class=""><code>libtree-sitter-json.so</code></li>
</ul>
</li>
<li class="">create packages for all the runtimes we want to support. All of them must be referenced by the main package.</li>
</ul>
<p>The purpose of these packages is to ensure that the project you are developing has access to the tree-sitter-library.</p>
<p>Now we can package the binding library which I called <code>TreeSitter.Bindings</code>, this package has a dependency on the <code>libtreesitter</code> meta-package. In order to make it work however after installing <code>TreeSitter.Bindings</code> a manual change is required in the csproj</p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">PropertyGroup</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">RuntimeIdentifier</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">Condition</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value punctuation" style="color:#393A34">'</span><span class="token tag attr-value" style="color:#e3116c">$(RuntimeIdentifier)' == ''</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">$(NETCoreSdkRuntimeIdentifier)</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">RuntimeIdentifier</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">PropertyGroup</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span></code></pre></div></div>
<p>This will indicate the correct runtime so that the meta-package reference will pick up the correct runtime package to be used.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-the-pieces-together">Getting the pieces together<a href="https://davidelettieri.it/2023/04/09/Tree-sitter-C-sharp-bindings#getting-the-pieces-together" class="hash-link" aria-label="Direct link to Getting the pieces together" title="Direct link to Getting the pieces together" translate="no">​</a></h2>
<p>This was roughly the steps I made to have a working sample:</p>
<ol>
<li class="">Build tree-sitter -&gt; as easy as cloning the repo and running <code>make</code></li>
<li class="">Build tree-sitter-json -&gt; same as above</li>
<li class="">Package the compiled libraries into the desired nuget packages using nuspec files</li>
<li class="">Generate the bindings for both tree-sitter and tree-sitter-json</li>
<li class="">Package the bindings in <code>TreeSitter.Bindings</code></li>
<li class="">Build a sample project reproducing the get started sample</li>
</ol>
<p>Sadly all of this was done manually, if I find the time to automate part of this process I might add all the other available grammars to the bindings.</p>
<p>That said the repo with all of this is <a href="https://github.com/davidelettieri/treesitter-bindings" target="_blank" rel="noopener noreferrer" class="">this one</a>. There is a working sample and the packages are available on my github source repo.</p>
<p>The C# reproduction is following the c sample very closely.</p>
<div class="language-csharp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-csharp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Diagnostics</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">TreeSitter</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Bindings</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Helpers</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">TreeSitter</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Bindings</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Json</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">TSBindingsJson</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token class-name">TreeSitter</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Bindings</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">TSBindings</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">unsafe</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> parser </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parser_new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">parser_set_language</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_sitter_json</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">MarshaledString</span><span class="token plain"> sourceCode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">MarshaledString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"[1, null]"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> tree </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">parser_parse_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        parser</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        sourceCode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">uint</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> sourceCode</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Length</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> rootNode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">tree_root_node</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> arrayNode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_named_child</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rootNode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> numberNode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_named_child</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arrayNode</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Debug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_type</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rootNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"document"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Debug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_type</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arrayNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"array"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Debug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_type</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">numberNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"number"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Debug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rootNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Debug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arrayNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Debug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_named_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">arrayNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Debug</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">node_child_count</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">numberNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> stringRep </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">node_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rootNode</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Console</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">WriteLine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Syntax tree: {0}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">stringRep</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">tree_delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">parser_delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parser</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>c#</category>
            <category>tree-sitter</category>
            <category>dotnet-bindings</category>
            <category>c#-bindings</category>
        </item>
    </channel>
</rss>